/* *
 *
 *  (c) 2010-2019 Torstein Honsi
 *
 *  License: www.highcharts.com/license
 *
 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
 *
 * */
"use strict";
import H from "./Globals.js";
/**
 * This is a placeholder type of the possible series options for
 * [Highcharts](../highcharts/series), [Highstock](../highstock/series),
 * [Highmaps](../highmaps/series), and [Gantt](../gantt/series).
 *
 * In TypeScript is this dynamically generated to reference all possible types
 * of series options.
 *
 * @ignore-declaration
 * @typedef {Highcharts.SeriesOptions|Highcharts.Dictionary<*>} Highcharts.SeriesOptionsType
 */
/**
 * Options for `dataSorting`.
 *
 * @interface Highcharts.DataSortingOptionsObject
 * @since 8.0.0
 */ /**
 * Enable or disable data sorting for the series.
 * @name Highcharts.DataSortingOptionsObject#enabled
 * @type {boolean|undefined}
 */ /**
 * Whether to allow matching points by name in an update.
 * @name Highcharts.DataSortingOptionsObject#matchByName
 * @type {boolean|undefined}
 */ /**
 * Determines what data value should be used to sort by.
 * @name Highcharts.DataSortingOptionsObject#sortKey
 * @type {string|undefined}
 */
/**
 * Function callback when a series has been animated.
 *
 * @callback Highcharts.SeriesAfterAnimateCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        The series where the event occured.
 *
 * @param {Highcharts.SeriesAfterAnimateEventObject} event
 *        Event arguments.
 */
/**
 * Event information regarding completed animation of a series.
 *
 * @interface Highcharts.SeriesAfterAnimateEventObject
 */ /**
 * Animated series.
 * @name Highcharts.SeriesAfterAnimateEventObject#target
 * @type {Highcharts.Series}
 */ /**
 * Event type.
 * @name Highcharts.SeriesAfterAnimateEventObject#type
 * @type {"afterAnimate"}
 */
/**
 * Function callback when the checkbox next to the series' name in the legend is
 * clicked.
 *
 * @callback Highcharts.SeriesCheckboxClickCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        The series where the event occured.
 *
 * @param {Highcharts.SeriesCheckboxClickEventObject} event
 *        Event arguments.
 */
/**
 * Event information regarding check of a series box.
 *
 * @interface Highcharts.SeriesCheckboxClickEventObject
 */ /**
 * Whether the box has been checked.
 * @name Highcharts.SeriesCheckboxClickEventObject#checked
 * @type {boolean}
 */ /**
 * Related series.
 * @name Highcharts.SeriesCheckboxClickEventObject#item
 * @type {Highcharts.Series}
 */ /**
 * Related series.
 * @name Highcharts.SeriesCheckboxClickEventObject#target
 * @type {Highcharts.Series}
 */ /**
 * Event type.
 * @name Highcharts.SeriesCheckboxClickEventObject#type
 * @type {"checkboxClick"}
 */
/**
 * Function callback when a series is clicked. Return false to cancel toogle
 * actions.
 *
 * @callback Highcharts.SeriesClickCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        The series where the event occured.
 *
 * @param {Highcharts.SeriesClickEventObject} event
 *        Event arguments.
 */
/**
 * Common information for a click event on a series.
 *
 * @interface Highcharts.SeriesClickEventObject
 * @extends global.Event
 */ /**
 * Nearest point on the graph.
 * @name Highcharts.SeriesClickEventObject#point
 * @type {Highcharts.Point}
 */
/**
 * Gets fired when the series is hidden after chart generation time, either by
 * clicking the legend item or by calling `.hide()`.
 *
 * @callback Highcharts.SeriesHideCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        The series where the event occured.
 *
 * @param {global.Event} event
 *        The event that occured.
 */
/**
 * The SVG value used for the `stroke-linecap` and `stroke-linejoin` of a line
 * graph.
 *
 * @typedef {"butt"|"round"|"square"|string} Highcharts.SeriesLinecapValue
 */
/**
 * Gets fired when the legend item belonging to the series is clicked. The
 * default action is to toggle the visibility of the series. This can be
 * prevented by returning `false` or calling `event.preventDefault()`.
 *
 * @callback Highcharts.SeriesLegendItemClickCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        The series where the event occured.
 *
 * @param {Highcharts.SeriesLegendItemClickEventObject} event
 *        The event that occured.
 */
/**
 * Information about the event.
 *
 * @interface Highcharts.SeriesLegendItemClickEventObject
 */ /**
 * Related browser event.
 * @name Highcharts.SeriesLegendItemClickEventObject#browserEvent
 * @type {global.PointerEvent}
 */ /**
 * Prevent the default action of toggle the visibility of the series.
 * @name Highcharts.SeriesLegendItemClickEventObject#preventDefault
 * @type {Function}
 */ /**
 * Related series.
 * @name Highcharts.SeriesCheckboxClickEventObject#target
 * @type {Highcharts.Series}
 */ /**
 * Event type.
 * @name Highcharts.SeriesCheckboxClickEventObject#type
 * @type {"checkboxClick"}
 */
/**
 * Gets fired when the mouse leaves the graph.
 *
 * @callback Highcharts.SeriesMouseOutCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        Series where the event occured.
 *
 * @param {global.PointerEvent} event
 *        Event that occured.
 */
/**
 * Gets fired when the mouse enters the graph.
 *
 * @callback Highcharts.SeriesMouseOverCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        Series where the event occured.
 *
 * @param {global.PointerEvent} event
 *        Event that occured.
 */
/**
 * Translation and scale for the plot area of a series.
 *
 * @interface Highcharts.SeriesPlotBoxObject
 */ /**
 * @name Highcharts.SeriesPlotBoxObject#scaleX
 * @type {number}
 */ /**
 * @name Highcharts.SeriesPlotBoxObject#scaleY
 * @type {number}
 */ /**
 * @name Highcharts.SeriesPlotBoxObject#translateX
 * @type {number}
 */ /**
 * @name Highcharts.SeriesPlotBoxObject#translateY
 * @type {number}
 */
/**
 * Gets fired when the series is shown after chart generation time, either by
 * clicking the legend item or by calling `.show()`.
 *
 * @callback Highcharts.SeriesShowCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        Series where the event occured.
 *
 * @param {global.Event} event
 *        Event that occured.
 */
/**
 * Possible key values for the series state options.
 *
 * @typedef {"hover"|"inactive"|"normal"|"select"} Highcharts.SeriesStateValue
 */
import U from "./Utilities.js";
var animObject = U.animObject,
  arrayMax = U.arrayMax,
  arrayMin = U.arrayMin,
  clamp = U.clamp,
  correctFloat = U.correctFloat,
  defined = U.defined,
  erase = U.erase,
  extend = U.extend,
  isArray = U.isArray,
  isNumber = U.isNumber,
  isString = U.isString,
  objectEach = U.objectEach,
  pick = U.pick,
  splat = U.splat,
  syncTimeout = U.syncTimeout;
import "./Options.js";
import "./Legend.js";
import "./Point.js";
import "./SvgRenderer.js";
var addEvent = H.addEvent,
  defaultOptions = H.defaultOptions,
  defaultPlotOptions = H.defaultPlotOptions,
  fireEvent = H.fireEvent,
  LegendSymbolMixin = H.LegendSymbolMixin, // @todo add as a requirement
  merge = H.merge,
  Point = H.Point, // @todo  add as a requirement
  removeEvent = H.removeEvent,
  SVGElement = H.SVGElement,
  win = H.win;
/**
 * This is the base series prototype that all other series types inherit from.
 * A new series is initialized either through the
 * [series](https://api.highcharts.com/highcharts/series)
 * option structure, or after the chart is initialized, through
 * {@link Highcharts.Chart#addSeries}.
 *
 * The object can be accessed in a number of ways. All series and point event
 * handlers give a reference to the `series` object. The chart object has a
 * {@link Highcharts.Chart#series|series} property that is a collection of all
 * the chart's series. The point objects and axis objects also have the same
 * reference.
 *
 * Another way to reference the series programmatically is by `id`. Add an id
 * in the series configuration options, and get the series object by
 * {@link Highcharts.Chart#get}.
 *
 * Configuration options for the series are given in three levels. Options for
 * all series in a chart are given in the
 * [plotOptions.series](https://api.highcharts.com/highcharts/plotOptions.series)
 * object. Then options for all series of a specific type
 * are given in the plotOptions of that type, for example `plotOptions.line`.
 * Next, options for one single series are given in the series array, or as
 * arguments to `chart.addSeries`.
 *
 * The data in the series is stored in various arrays.
 *
 * - First, `series.options.data` contains all the original config options for
 *   each point whether added by options or methods like `series.addPoint`.
 *
 * - Next, `series.data` contains those values converted to points, but in case
 *   the series data length exceeds the `cropThreshold`, or if the data is
 *   grouped, `series.data` doesn't contain all the points. It only contains the
 *   points that have been created on demand.
 *
 * - Then there's `series.points` that contains all currently visible point
 *   objects. In case of cropping, the cropped-away points are not part of this
 *   array. The `series.points` array starts at `series.cropStart` compared to
 *   `series.data` and `series.options.data`. If however the series data is
 *   grouped, these can't be correlated one to one.
 *
 * - `series.xData` and `series.processedXData` contain clean x values,
 *   equivalent to `series.data` and `series.points`.
 *
 * - `series.yData` and `series.processedYData` contain clean y values,
 *   equivalent to `series.data` and `series.points`.
 *
 * @class
 * @name Highcharts.Series
 *
 * @param {Highcharts.Chart} chart
 *        The chart instance.
 *
 * @param {Highcharts.SeriesOptionsType|object} options
 *        The series options.
 */ /**
 * The line series is the base type and is therefor the series base prototype.
 *
 * @private
 * @class
 * @name Highcharts.seriesTypes.line
 *
 * @augments Highcharts.Series
 */
H.Series = H.seriesType(
  "line",
  /**
   * Series options for specific data and the data itself. In TypeScript you
   * have to cast the series options to specific series types, to get all
   * possible options for a series.
   *
   * @example
   * // TypeScript example
   * Highcharts.chart('container', {
   *     series: [{
   *         color: '#06C',
   *         data: [[0, 1], [2, 3]]
   *     } as Highcharts.SeriesLineOptions ]
   * });
   *
   * @type      {Array<*>}
   * @apioption series
   */
  /**
   * An id for the series. This can be used after render time to get a pointer
   * to the series object through `chart.get()`.
   *
   * @sample {highcharts} highcharts/plotoptions/series-id/
   *         Get series by id
   *
   * @type      {string}
   * @since     1.2.0
   * @apioption series.id
   */
  /**
   * The index of the series in the chart, affecting the internal index in the
   * `chart.series` array, the visible Z index as well as the order in the
   * legend.
   *
   * @type      {number}
   * @since     2.3.0
   * @apioption series.index
   */
  /**
   * The sequential index of the series in the legend.
   *
   * @see [legend.reversed](#legend.reversed),
   *      [yAxis.reversedStacks](#yAxis.reversedStacks)
   *
   * @sample {highcharts|highstock} highcharts/series/legendindex/
   *         Legend in opposite order
   *
   * @type      {number}
   * @apioption series.legendIndex
   */
  /**
   * The name of the series as shown in the legend, tooltip etc.
   *
   * @sample {highcharts} highcharts/series/name/
   *         Series name
   * @sample {highmaps} maps/demo/category-map/
   *         Series name
   *
   * @type      {string}
   * @apioption series.name
   */
  /**
   * This option allows grouping series in a stacked chart. The stack option
   * can be a string or anything else, as long as the grouped series' stack
   * options match each other after conversion into a string.
   *
   * @sample {highcharts} highcharts/series/stack/
   *         Stacked and grouped columns
   *
   * @type      {number|string}
   * @since     2.1
   * @product   highcharts highstock
   * @apioption series.stack
   */
  /**
   * The type of series, for example `line` or `column`. By default, the
   * series type is inherited from [chart.type](#chart.type), so unless the
   * chart is a combination of series types, there is no need to set it on the
   * series level.
   *
   * @sample {highcharts} highcharts/series/type/
   *         Line and column in the same chart
   * @sample highcharts/series/type-dynamic/
   *         Dynamic types with button selector
   * @sample {highmaps} maps/demo/mapline-mappoint/
   *         Multiple types in the same map
   *
   * @type      {string}
   * @apioption series.type
   */
  /**
   * When using dual or multiple x axes, this number defines which xAxis the
   * particular series is connected to. It refers to either the
   * {@link #xAxis.id|axis id}
   * or the index of the axis in the xAxis array, with 0 being the first.
   *
   * @type      {number|string}
   * @default   0
   * @product   highcharts highstock
   * @apioption series.xAxis
   */
  /**
   * When using dual or multiple y axes, this number defines which yAxis the
   * particular series is connected to. It refers to either the
   * {@link #yAxis.id|axis id}
   * or the index of the axis in the yAxis array, with 0 being the first.
   *
   * @sample {highcharts} highcharts/series/yaxis/
   *         Apply the column series to the secondary Y axis
   *
   * @type      {number|string}
   * @default   0
   * @product   highcharts highstock
   * @apioption series.yAxis
   */
  /**
   * Define the visual z index of the series.
   *
   * @sample {highcharts} highcharts/plotoptions/series-zindex-default/
   *         With no z index, the series defined last are on top
   * @sample {highcharts} highcharts/plotoptions/series-zindex/
   *         With a z index, the series with the highest z index is on top
   * @sample {highstock} highcharts/plotoptions/series-zindex-default/
   *         With no z index, the series defined last are on top
   * @sample {highstock} highcharts/plotoptions/series-zindex/
   *         With a z index, the series with the highest z index is on top
   *
   * @type      {number}
   * @product   highcharts highstock
   * @apioption series.zIndex
   */
  null,
  /**
   * General options for all series types.
   *
   * @optionparent plotOptions.series
   */
  {
    /**
     * The SVG value used for the `stroke-linecap` and `stroke-linejoin`
     * of a line graph. Round means that lines are rounded in the ends and
     * bends.
     *
     * @type       {Highcharts.SeriesLinecapValue}
     * @default    round
     * @since      3.0.7
     * @apioption  plotOptions.line.linecap
     */
    /**
     * Pixel width of the graph line.
     *
     * @see In styled mode, the line stroke-width can be set with the
     *      `.highcharts-graph` class name.
     *
     * @sample {highcharts} highcharts/plotoptions/series-linewidth-general/
     *         On all series
     * @sample {highcharts} highcharts/plotoptions/series-linewidth-specific/
     *         On one single series
     *
     * @product highcharts highstock
     *
     * @private
     */
    lineWidth: 2,
    /**
     * For some series, there is a limit that shuts down initial animation
     * by default when the total number of points in the chart is too high.
     * For example, for a column chart and its derivatives, animation does
     * not run if there is more than 250 points totally. To disable this
     * cap, set `animationLimit` to `Infinity`.
     *
     * @type      {number}
     * @apioption plotOptions.series.animationLimit
     */
    /**
     * Allow this series' points to be selected by clicking on the graphic
     * (columns, point markers, pie slices, map areas etc).
     *
     * The selected points can be handled by point select and unselect
     * events, or collectively by the [getSelectedPoints](
     * Highcharts.Chart#getSelectedPoints) function.
     *
     * And alternative way of selecting points is through dragging.
     *
     * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-line/
     *         Line
     * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-column/
     *         Column
     * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-pie/
     *         Pie
     * @sample {highcharts} highcharts/chart/events-selection-points/
     *         Select a range of points through a drag selection
     * @sample {highmaps} maps/plotoptions/series-allowpointselect/
     *         Map area
     * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/
     *         Map bubble
     *
     * @since 1.2.0
     *
     * @private
     */
    allowPointSelect: false,
    /**
     * If true, a checkbox is displayed next to the legend item to allow
     * selecting the series. The state of the checkbox is determined by
     * the `selected` option.
     *
     * @productdesc {highmaps}
     * Note that if a `colorAxis` is defined, the color axis is represented
     * in the legend, not the series.
     *
     * @sample {highcharts} highcharts/plotoptions/series-showcheckbox-true/
     *         Show select box
     *
     * @since 1.2.0
     *
     * @private
     */
    showCheckbox: false,
    /**
     * Enable or disable the initial animation when a series is displayed.
     * The animation can also be set as a configuration object. Please
     * note that this option only applies to the initial animation of the
     * series itself. For other animations, see [chart.animation](
     * #chart.animation) and the animation parameter under the API methods.
     * The following properties are supported:
     *
     * - `duration`: The duration of the animation in milliseconds.
     *
     * - `easing`: Can be a string reference to an easing function set on
     *   the `Math` object or a function. See the _Custom easing function_
     *   demo below.
     *
     * Due to poor performance, animation is disabled in old IE browsers
     * for several chart types.
     *
     * @sample {highcharts} highcharts/plotoptions/series-animation-disabled/
     *         Animation disabled
     * @sample {highcharts} highcharts/plotoptions/series-animation-slower/
     *         Slower animation
     * @sample {highcharts} highcharts/plotoptions/series-animation-easing/
     *         Custom easing function
     * @sample {highstock} stock/plotoptions/animation-slower/
     *         Slower animation
     * @sample {highstock} stock/plotoptions/animation-easing/
     *         Custom easing function
     * @sample {highmaps} maps/plotoptions/series-animation-true/
     *         Animation enabled on map series
     * @sample {highmaps} maps/plotoptions/mapbubble-animation-false/
     *         Disabled on mapbubble series
     *
     * @type    {boolean|Highcharts.AnimationOptionsObject}
     * @default {highcharts} true
     * @default {highstock} true
     * @default {highmaps} false
     *
     * @private
     */
    animation: {
      /** @internal */
      duration: 1000,
    },
    /**
     * An additional class name to apply to the series' graphical elements.
     * This option does not replace default class names of the graphical
     * element.
     *
     * @type      {string}
     * @since     5.0.0
     * @apioption plotOptions.series.className
     */
    /**
     * Disable this option to allow series rendering in the whole plotting
     * area.
     *
     * **Note:** Clipping should be always enabled when
     * [chart.zoomType](#chart.zoomType) is set
     *
     * @sample {highcharts} highcharts/plotoptions/series-clip/
     *         Disabled clipping
     *
     * @default   true
     * @type      {boolean}
     * @since     3.0.0
     * @apioption plotOptions.series.clip
     */
    /**
     * The main color of the series. In line type series it applies to the
     * line and the point markers unless otherwise specified. In bar type
     * series it applies to the bars unless a color is specified per point.
     * The default value is pulled from the `options.colors` array.
     *
     * In styled mode, the color can be defined by the
     * [colorIndex](#plotOptions.series.colorIndex) option. Also, the series
     * color can be set with the `.highcharts-series`,
     * `.highcharts-color-{n}`, `.highcharts-{type}-series` or
     * `.highcharts-series-{n}` class, or individual classes given by the
     * `className` option.
     *
     * @productdesc {highmaps}
     * In maps, the series color is rarely used, as most choropleth maps use
     * the color to denote the value of each point. The series color can
     * however be used in a map with multiple series holding categorized
     * data.
     *
     * @sample {highcharts} highcharts/plotoptions/series-color-general/
     *         General plot option
     * @sample {highcharts} highcharts/plotoptions/series-color-specific/
     *         One specific series
     * @sample {highcharts} highcharts/plotoptions/series-color-area/
     *         Area color
     * @sample {highcharts} highcharts/series/infographic/
     *         Pattern fill
     * @sample {highmaps} maps/demo/category-map/
     *         Category map by multiple series
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @apioption plotOptions.series.color
     */
    /**
     * Styled mode only. A specific color index to use for the series, so
     * its graphic representations are given the class name
     * `highcharts-color-{n}`.
     *
     * @type      {number}
     * @since     5.0.0
     * @apioption plotOptions.series.colorIndex
     */
    /**
     * Whether to connect a graph line across null points, or render a gap
     * between the two points on either side of the null.
     *
     * @sample {highcharts} highcharts/plotoptions/series-connectnulls-false/
     *         False by default
     * @sample {highcharts} highcharts/plotoptions/series-connectnulls-true/
     *         True
     *
     * @type      {boolean}
     * @default   false
     * @product   highcharts highstock
     * @apioption plotOptions.series.connectNulls
     */
    /**
     * You can set the cursor to "pointer" if you have click events attached
     * to the series, to signal to the user that the points and lines can
     * be clicked.
     *
     * In styled mode, the series cursor can be set with the same classes
     * as listed under [series.color](#plotOptions.series.color).
     *
     * @sample {highcharts} highcharts/plotoptions/series-cursor-line/
     *         On line graph
     * @sample {highcharts} highcharts/plotoptions/series-cursor-column/
     *         On columns
     * @sample {highcharts} highcharts/plotoptions/series-cursor-scatter/
     *         On scatter markers
     * @sample {highstock} stock/plotoptions/cursor/
     *         Pointer on a line graph
     * @sample {highmaps} maps/plotoptions/series-allowpointselect/
     *         Map area
     * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/
     *         Map bubble
     *
     * @type      {string|Highcharts.CursorValue}
     * @apioption plotOptions.series.cursor
     */
    /**
     * A name for the dash style to use for the graph, or for some series
     * types the outline of each shape.
     *
     * In styled mode, the
     * [stroke dash-array](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/series-dashstyle/)
     * can be set with the same classes as listed under
     * [series.color](#plotOptions.series.color).
     *
     * @sample {highcharts} highcharts/plotoptions/series-dashstyle-all/
     *         Possible values demonstrated
     * @sample {highcharts} highcharts/plotoptions/series-dashstyle/
     *         Chart suitable for printing in black and white
     * @sample {highstock} highcharts/plotoptions/series-dashstyle-all/
     *         Possible values demonstrated
     * @sample {highmaps} highcharts/plotoptions/series-dashstyle-all/
     *         Possible values demonstrated
     * @sample {highmaps} maps/plotoptions/series-dashstyle/
     *         Dotted borders on a map
     *
     * @type      {Highcharts.DashStyleValue}
     * @default   Solid
     * @since     2.1
     * @apioption plotOptions.series.dashStyle
     */
    /**
     * A description of the series to add to the screen reader information
     * about the series.
     *
     * @type      {string}
     * @since     5.0.0
     * @requires  modules/accessibility
     * @apioption plotOptions.series.description
     */
    /**
     * Options for the series data sorting.
     *
     * @type      {Highcharts.DataSortingOptionsObject}
     * @since     8.0.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.dataSorting
     */
    /**
     * Enable or disable data sorting for the series. Use [xAxis.reversed](
     * #xAxis.reversed) to change the sorting order.
     *
     * @sample {highcharts} highcharts/datasorting/animation/
     *         Data sorting in scatter-3d
     * @sample {highcharts} highcharts/datasorting/labels-animation/
     *         Axis labels animation
     * @sample {highcharts} highcharts/datasorting/dependent-sorting/
     *         Dependent series sorting
     * @sample {highcharts} highcharts/datasorting/independent-sorting/
     *         Independent series sorting
     *
     * @type      {boolean}
     * @since     8.0.0
     * @apioption plotOptions.series.dataSorting.enabled
     */
    /**
     * Whether to allow matching points by name in an update. If this option
     * is disabled, points will be matched by order.
     *
     * @sample {highcharts} highcharts/datasorting/match-by-name/
     *         Enabled match by name
     *
     * @type      {boolean}
     * @since     8.0.0
     * @apioption plotOptions.series.dataSorting.matchByName
     */
    /**
     * Determines what data value should be used to sort by.
     *
     * @sample {highcharts} highcharts/datasorting/sort-key/
     *         Sort key as `z` value
     *
     * @type      {string}
     * @since     8.0.0
     * @default   y
     * @apioption plotOptions.series.dataSorting.sortKey
     */
    /**
     * Enable or disable the mouse tracking for a specific series. This
     * includes point tooltips and click events on graphs and points. For
     * large datasets it improves performance.
     *
     * @sample {highcharts} highcharts/plotoptions/series-enablemousetracking-false/
     *         No mouse tracking
     * @sample {highmaps} maps/plotoptions/series-enablemousetracking-false/
     *         No mouse tracking
     *
     * @type      {boolean}
     * @default   true
     * @apioption plotOptions.series.enableMouseTracking
     */
    /**
     * Whether to use the Y extremes of the total chart width or only the
     * zoomed area when zooming in on parts of the X axis. By default, the
     * Y axis adjusts to the min and max of the visible data. Cartesian
     * series only.
     *
     * @type      {boolean}
     * @default   false
     * @since     4.1.6
     * @product   highcharts highstock gantt
     * @apioption plotOptions.series.getExtremesFromAll
     */
    /**
     * An array specifying which option maps to which key in the data point
     * array. This makes it convenient to work with unstructured data arrays
     * from different sources.
     *
     * @see [series.data](#series.line.data)
     *
     * @sample {highcharts|highstock} highcharts/series/data-keys/
     *         An extended data array with keys
     * @sample {highcharts|highstock} highcharts/series/data-nested-keys/
     *         Nested keys used to access object properties
     *
     * @type      {Array<string>}
     * @since     4.1.6
     * @apioption plotOptions.series.keys
     */
    /**
     * The line cap used for line ends and line joins on the graph.
     *
     * @type       {Highcharts.SeriesLinecapValue}
     * @default    round
     * @product    highcharts highstock
     * @apioption  plotOptions.series.linecap
     */
    /**
     * The [id](#series.id) of another series to link to. Additionally,
     * the value can be ":previous" to link to the previous series. When
     * two series are linked, only the first one appears in the legend.
     * Toggling the visibility of this also toggles the linked series.
     *
     * If master series uses data sorting and linked series does not have
     * its own sorting definition, the linked series will be sorted in the
     * same order as the master one.
     *
     * @sample {highcharts|highstock} highcharts/demo/arearange-line/
     *         Linked series
     *
     * @type      {string}
     * @since     3.0
     * @product   highcharts highstock gantt
     * @apioption plotOptions.series.linkedTo
     */
    /**
     * Options for the corresponding navigator series if `showInNavigator`
     * is `true` for this series. Available options are the same as any
     * series, documented at [plotOptions](#plotOptions.series) and
     * [series](#series).
     *
     * These options are merged with options in [navigator.series](
     * #navigator.series), and will take precedence if the same option is
     * defined both places.
     *
     * @see [navigator.series](#navigator.series)
     *
     * @type      {Highcharts.PlotSeriesOptions}
     * @since     5.0.0
     * @product   highstock
     * @apioption plotOptions.series.navigatorOptions
     */
    /**
     * The color for the parts of the graph or points that are below the
     * [threshold](#plotOptions.series.threshold). Note that `zones` takes
     * precedence over the negative color. Using `negativeColor` is
     * equivalent to applying a zone with value of 0.
     *
     * @see In styled mode, a negative color is applied by setting this option
     *      to `true` combined with the `.highcharts-negative` class name.
     *
     * @sample {highcharts} highcharts/plotoptions/series-negative-color/
     *         Spline, area and column
     * @sample {highcharts} highcharts/plotoptions/arearange-negativecolor/
     *         Arearange
     * @sample {highcharts} highcharts/css/series-negative-color/
     *         Styled mode
     * @sample {highstock} highcharts/plotoptions/series-negative-color/
     *         Spline, area and column
     * @sample {highstock} highcharts/plotoptions/arearange-negativecolor/
     *         Arearange
     * @sample {highmaps} highcharts/plotoptions/series-negative-color/
     *         Spline, area and column
     * @sample {highmaps} highcharts/plotoptions/arearange-negativecolor/
     *         Arearange
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since     3.0
     * @apioption plotOptions.series.negativeColor
     */
    /**
     * Same as
     * [accessibility.pointDescriptionFormatter](#accessibility.pointDescriptionFormatter),
     * but for an individual series. Overrides the chart wide configuration.
     *
     * @type      {Function}
     * @since     5.0.12
     * @apioption plotOptions.series.pointDescriptionFormatter
     */
    /**
     * If no x values are given for the points in a series, `pointInterval`
     * defines the interval of the x values. For example, if a series
     * contains one value every decade starting from year 0, set
     * `pointInterval` to `10`. In true `datetime` axes, the `pointInterval`
     * is set in milliseconds.
     *
     * It can be also be combined with `pointIntervalUnit` to draw irregular
     * time intervals.
     *
     * Please note that this options applies to the _series data_, not the
     * interval of the axis ticks, which is independent.
     *
     * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/
     *         Datetime X axis
     * @sample {highstock} stock/plotoptions/pointinterval-pointstart/
     *         Using pointStart and pointInterval
     *
     * @type      {number}
     * @default   1
     * @product   highcharts highstock gantt
     * @apioption plotOptions.series.pointInterval
     */
    /**
     * On datetime series, this allows for setting the
     * [pointInterval](#plotOptions.series.pointInterval) to irregular time
     * units, `day`, `month` and `year`. A day is usually the same as 24
     * hours, but `pointIntervalUnit` also takes the DST crossover into
     * consideration when dealing with local time. Combine this option with
     * `pointInterval` to draw weeks, quarters, 6 months, 10 years etc.
     *
     * Please note that this options applies to the _series data_, not the
     * interval of the axis ticks, which is independent.
     *
     * @sample {highcharts} highcharts/plotoptions/series-pointintervalunit/
     *         One point a month
     * @sample {highstock} highcharts/plotoptions/series-pointintervalunit/
     *         One point a month
     *
     * @type       {string}
     * @since      4.1.0
     * @product    highcharts highstock gantt
     * @validvalue ["day", "month", "year"]
     * @apioption  plotOptions.series.pointIntervalUnit
     */
    /**
     * Possible values: `"on"`, `"between"`, `number`.
     *
     * In a column chart, when pointPlacement is `"on"`, the point will not
     * create any padding of the X axis. In a polar column chart this means
     * that the first column points directly north. If the pointPlacement is
     * `"between"`, the columns will be laid out between ticks. This is
     * useful for example for visualising an amount between two points in
     * time or in a certain sector of a polar chart.
     *
     * Since Highcharts 3.0.2, the point placement can also be numeric,
     * where 0 is on the axis value, -0.5 is between this value and the
     * previous, and 0.5 is between this value and the next. Unlike the
     * textual options, numeric point placement options won't affect axis
     * padding.
     *
     * Note that pointPlacement needs a [pointRange](
     * #plotOptions.series.pointRange) to work. For column series this is
     * computed, but for line-type series it needs to be set.
     *
     * For the `xrange` series type and gantt charts, if the Y axis is a
     * category axis, the `pointPlacement` applies to the Y axis rather than
     * the (typically datetime) X axis.
     *
     * Defaults to `undefined` in cartesian charts, `"between"` in polar
     * charts.
     *
     * @see [xAxis.tickmarkPlacement](#xAxis.tickmarkPlacement)
     *
     * @sample {highcharts|highstock} highcharts/plotoptions/series-pointplacement-between/
     *         Between in a column chart
     * @sample {highcharts|highstock} highcharts/plotoptions/series-pointplacement-numeric/
     *         Numeric placement for custom layout
     * @sample {highcharts|highstock} maps/plotoptions/heatmap-pointplacement/
     *         Placement in heatmap
     *
     * @type      {string|number}
     * @since     2.3.0
     * @product   highcharts highstock gantt
     * @apioption plotOptions.series.pointPlacement
     */
    /**
     * If no x values are given for the points in a series, pointStart
     * defines on what value to start. For example, if a series contains one
     * yearly value starting from 1945, set pointStart to 1945.
     *
     * @sample {highcharts} highcharts/plotoptions/series-pointstart-linear/
     *         Linear
     * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/
     *         Datetime
     * @sample {highstock} stock/plotoptions/pointinterval-pointstart/
     *         Using pointStart and pointInterval
     *
     * @type      {number}
     * @default   0
     * @product   highcharts highstock gantt
     * @apioption plotOptions.series.pointStart
     */
    /**
     * Whether to select the series initially. If `showCheckbox` is true,
     * the checkbox next to the series name in the legend will be checked
     * for a selected series.
     *
     * @sample {highcharts} highcharts/plotoptions/series-selected/
     *         One out of two series selected
     *
     * @type      {boolean}
     * @default   false
     * @since     1.2.0
     * @apioption plotOptions.series.selected
     */
    /**
     * Whether to apply a drop shadow to the graph line. Since 2.3 the
     * shadow can be an object configuration containing `color`, `offsetX`,
     * `offsetY`, `opacity` and `width`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-shadow/
     *         Shadow enabled
     *
     * @type      {boolean|Highcharts.ShadowOptionsObject}
     * @default   false
     * @apioption plotOptions.series.shadow
     */
    /**
     * Whether to display this particular series or series type in the
     * legend. Standalone series are shown in legend by default, and linked
     * series are not. Since v7.2.0 it is possible to show series that use
     * colorAxis by setting this option to `true`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-showinlegend/
     *         One series in the legend, one hidden
     *
     * @type      {boolean}
     * @apioption plotOptions.series.showInLegend
     */
    /**
     * Whether or not to show the series in the navigator. Takes precedence
     * over [navigator.baseSeries](#navigator.baseSeries) if defined.
     *
     * @type      {boolean}
     * @since     5.0.0
     * @product   highstock
     * @apioption plotOptions.series.showInNavigator
     */
    /**
     * If set to `true`, the accessibility module will skip past the points
     * in this series for keyboard navigation.
     *
     * @type      {boolean}
     * @since     5.0.12
     * @apioption plotOptions.series.skipKeyboardNavigation
     */
    /**
     * Whether to stack the values of each series on top of each other.
     * Possible values are `undefined` to disable, `"normal"` to stack by
     * value or `"percent"`. When stacking is enabled, data must be sorted
     * in ascending X order. A special stacking option is with the
     * streamgraph series type, where the stacking option is set to
     * `"stream"`. The second one is `"overlap"`, which only applies to
     * waterfall series.
     *
     * @see [yAxis.reversedStacks](#yAxis.reversedStacks)
     *
     * @sample {highcharts} highcharts/plotoptions/series-stacking-line/
     *         Line
     * @sample {highcharts} highcharts/plotoptions/series-stacking-column/
     *         Column
     * @sample {highcharts} highcharts/plotoptions/series-stacking-bar/
     *         Bar
     * @sample {highcharts} highcharts/plotoptions/series-stacking-area/
     *         Area
     * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-line/
     *         Line
     * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-column/
     *         Column
     * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-bar/
     *         Bar
     * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-area/
     *         Area
     * @sample {highcharts} highcharts/plotoptions/series-waterfall-with-normal-stacking
     *         Waterfall with normal stacking
     * @sample {highcharts} highcharts/plotoptions/series-waterfall-with-overlap-stacking
     *         Waterfall with overlap stacking
     * @sample {highstock} stock/plotoptions/stacking/
     *         Area
     *
     * @type       {string}
     * @product    highcharts highstock
     * @validvalue ["normal", "overlap", "percent", "stream"]
     * @apioption  plotOptions.series.stacking
     */
    /**
     * Whether to apply steps to the line. Possible values are `left`,
     * `center` and `right`.
     *
     * @sample {highcharts} highcharts/plotoptions/line-step/
     *         Different step line options
     * @sample {highcharts} highcharts/plotoptions/area-step/
     *         Stepped, stacked area
     * @sample {highstock} stock/plotoptions/line-step/
     *         Step line
     *
     * @type       {string}
     * @since      1.2.5
     * @product    highcharts highstock
     * @validvalue ["left", "center", "right"]
     * @apioption  plotOptions.series.step
     */
    /**
     * The threshold, also called zero level or base level. For line type
     * series this is only used in conjunction with
     * [negativeColor](#plotOptions.series.negativeColor).
     *
     * @see [softThreshold](#plotOptions.series.softThreshold).
     *
     * @type      {number}
     * @default   0
     * @since     3.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.threshold
     */
    /**
     * Set the initial visibility of the series.
     *
     * @sample {highcharts} highcharts/plotoptions/series-visible/
     *         Two series, one hidden and one visible
     * @sample {highstock} stock/plotoptions/series-visibility/
     *         Hidden series
     *
     * @type      {boolean}
     * @default   true
     * @apioption plotOptions.series.visible
     */
    /**
     * Defines the Axis on which the zones are applied.
     *
     * @see [zones](#plotOptions.series.zones)
     *
     * @sample {highcharts} highcharts/series/color-zones-zoneaxis-x/
     *         Zones on the X-Axis
     * @sample {highstock} highcharts/series/color-zones-zoneaxis-x/
     *         Zones on the X-Axis
     *
     * @type      {string}
     * @default   y
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zoneAxis
     */
    /**
     * General event handlers for the series items. These event hooks can
     * also be attached to the series at run time using the
     * `Highcharts.addEvent` function.
     *
     * @declare Highcharts.SeriesEventsOptionsObject
     *
     * @private
     */
    events: {},
    /**
     * Fires after the series has finished its initial animation, or in case
     * animation is disabled, immediately as the series is displayed.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-afteranimate/
     *         Show label after animate
     * @sample {highstock} highcharts/plotoptions/series-events-afteranimate/
     *         Show label after animate
     *
     * @type      {Highcharts.SeriesAfterAnimateCallbackFunction}
     * @since     4.0
     * @product   highcharts highstock gantt
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.afterAnimate
     */
    /**
     * Fires when the checkbox next to the series' name in the legend is
     * clicked. One parameter, `event`, is passed to the function. The state
     * of the checkbox is found by `event.checked`. The checked item is
     * found by `event.item`. Return `false` to prevent the default action
     * which is to toggle the select state of the series.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-checkboxclick/
     *         Alert checkbox status
     *
     * @type      {Highcharts.SeriesCheckboxClickCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.checkboxClick
     */
    /**
     * Fires when the series is clicked. One parameter, `event`, is passed
     * to the function, containing common event information. Additionally,
     * `event.point` holds a pointer to the nearest point on the graph.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-click/
     *         Alert click info
     * @sample {highstock} stock/plotoptions/series-events-click/
     *         Alert click info
     * @sample {highmaps} maps/plotoptions/series-events-click/
     *         Display click info in subtitle
     *
     * @type      {Highcharts.SeriesClickCallbackFunction}
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.click
     */
    /**
     * Fires when the series is hidden after chart generation time, either
     * by clicking the legend item or by calling `.hide()`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-hide/
     *         Alert when the series is hidden by clicking the legend item
     *
     * @type      {Highcharts.SeriesHideCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.hide
     */
    /**
     * Fires when the legend item belonging to the series is clicked. One
     * parameter, `event`, is passed to the function. The default action
     * is to toggle the visibility of the series. This can be prevented
     * by returning `false` or calling `event.preventDefault()`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-legenditemclick/
     *         Confirm hiding and showing
     *
     * @type      {Highcharts.SeriesLegendItemClickCallbackFunction}
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.legendItemClick
     */
    /**
     * Fires when the mouse leaves the graph. One parameter, `event`, is
     * passed to the function, containing common event information. If the
     * [stickyTracking](#plotOptions.series) option is true, `mouseOut`
     * doesn't happen before the mouse enters another graph or leaves the
     * plot area.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-sticky/
     *         With sticky tracking by default
     * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-no-sticky/
     *         Without sticky tracking
     *
     * @type      {Highcharts.SeriesMouseOutCallbackFunction}
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.mouseOut
     */
    /**
     * Fires when the mouse enters the graph. One parameter, `event`, is
     * passed to the function, containing common event information.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-sticky/
     *         With sticky tracking by default
     * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-no-sticky/
     *         Without sticky tracking
     *
     * @type      {Highcharts.SeriesMouseOverCallbackFunction}
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.mouseOver
     */
    /**
     * Fires when the series is shown after chart generation time, either
     * by clicking the legend item or by calling `.show()`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-show/
     *         Alert when the series is shown by clicking the legend item.
     *
     * @type      {Highcharts.SeriesShowCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.show
     */
    /**
     * Options for the point markers of line-like series. Properties like
     * `fillColor`, `lineColor` and `lineWidth` define the visual appearance
     * of the markers. Other series types, like column series, don't have
     * markers, but have visual options on the series level instead.
     *
     * In styled mode, the markers can be styled with the
     * `.highcharts-point`, `.highcharts-point-hover` and
     * `.highcharts-point-select` class names.
     *
     * @declare Highcharts.PointMarkerOptionsObject
     *
     * @private
     */
    marker: {
      /**
       * Enable or disable the point marker. If `undefined`, the markers
       * are hidden when the data is dense, and shown for more widespread
       * data points.
       *
       * @sample {highcharts} highcharts/plotoptions/series-marker-enabled/
       *         Disabled markers
       * @sample {highcharts} highcharts/plotoptions/series-marker-enabled-false/
       *         Disabled in normal state but enabled on hover
       * @sample {highstock} stock/plotoptions/series-marker/
       *         Enabled markers
       *
       * @type      {boolean}
       * @default   {highcharts} undefined
       * @default   {highstock} false
       * @apioption plotOptions.series.marker.enabled
       */
      /**
       * The threshold for how dense the point markers should be before
       * they are hidden, given that `enabled` is not defined. The number
       * indicates the horizontal distance between the two closest points
       * in the series, as multiples of the `marker.radius`. In other
       * words, the default value of 2 means points are hidden if
       * overlapping horizontally.
       *
       * @sample highcharts/plotoptions/series-marker-enabledthreshold
       *         A higher threshold
       *
       * @since 6.0.5
       */
      enabledThreshold: 2,
      /**
       * The fill color of the point marker. When `undefined`, the series'
       * or point's color is used.
       *
       * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
       *         White fill
       *
       * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @apioption plotOptions.series.marker.fillColor
       */
      /**
       * Image markers only. Set the image width explicitly. When using
       * this option, a `width` must also be set.
       *
       * @sample {highcharts} highcharts/plotoptions/series-marker-width-height/
       *         Fixed width and height
       * @sample {highstock} highcharts/plotoptions/series-marker-width-height/
       *         Fixed width and height
       *
       * @type      {number}
       * @since     4.0.4
       * @apioption plotOptions.series.marker.height
       */
      /**
       * The color of the point marker's outline. When `undefined`, the
       * series' or point's color is used.
       *
       * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
       *         Inherit from series color (undefined)
       *
       * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       */
      lineColor: "#ffffff",
      /**
       * The width of the point marker's outline.
       *
       * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
       *         2px blue marker
       */
      lineWidth: 0,
      /**
       * The radius of the point marker.
       *
       * @sample {highcharts} highcharts/plotoptions/series-marker-radius/
       *         Bigger markers
       *
       * @default {highstock} 2
       */
      radius: 4,
      /**
       * A predefined shape or symbol for the marker. When undefined, the
       * symbol is pulled from options.symbols. Other possible values are
       * `'circle'`, `'square'`,`'diamond'`, `'triangle'` and
       * `'triangle-down'`.
       *
       * Additionally, the URL to a graphic can be given on this form:
       * `'url(graphic.png)'`. Note that for the image to be applied to
       * exported charts, its URL needs to be accessible by the export
       * server.
       *
       * Custom callbacks for symbol path generation can also be added to
       * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
       * used by its method name, as shown in the demo.
       *
       * @sample {highcharts} highcharts/plotoptions/series-marker-symbol/
       *         Predefined, graphic and custom markers
       * @sample {highstock} highcharts/plotoptions/series-marker-symbol/
       *         Predefined, graphic and custom markers
       *
       * @type      {string}
       * @apioption plotOptions.series.marker.symbol
       */
      /**
       * Image markers only. Set the image width explicitly. When using
       * this option, a `height` must also be set.
       *
       * @sample {highcharts} highcharts/plotoptions/series-marker-width-height/
       *         Fixed width and height
       * @sample {highstock} highcharts/plotoptions/series-marker-width-height/
       *         Fixed width and height
       *
       * @type      {number}
       * @since     4.0.4
       * @apioption plotOptions.series.marker.width
       */
      /**
       * States for a single point marker.
       *
       * @declare Highcharts.PointStatesOptionsObject
       */
      states: {
        /**
         * The normal state of a single point marker. Currently only
         * used for setting animation when returning to normal state
         * from hover.
         *
         * @declare Highcharts.PointStatesNormalOptionsObject
         */
        normal: {
          /**
           * Animation when returning to normal state after hovering.
           *
           * @type {boolean|Highcharts.AnimationOptionsObject}
           */
          animation: true,
        },
        /**
         * The hover state for a single point marker.
         *
         * @declare Highcharts.PointStatesHoverOptionsObject
         */
        hover: {
          /**
           * Animation when hovering over the marker.
           *
           * @type {boolean|Highcharts.AnimationOptionsObject}
           */
          animation: {
            /** @internal */
            duration: 50,
          },
          /**
           * Enable or disable the point marker.
           *
           * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-enabled/
           *         Disabled hover state
           */
          enabled: true,
          /**
           * The fill color of the marker in hover state. When
           * `undefined`, the series' or point's fillColor for normal
           * state is used.
           *
           * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
           * @apioption plotOptions.series.marker.states.hover.fillColor
           */
          /**
           * The color of the point marker's outline. When
           * `undefined`, the series' or point's lineColor for normal
           * state is used.
           *
           * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-linecolor/
           *         White fill color, black line color
           *
           * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
           * @apioption plotOptions.series.marker.states.hover.lineColor
           */
          /**
           * The width of the point marker's outline. When
           * `undefined`, the series' or point's lineWidth for normal
           * state is used.
           *
           * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-linewidth/
           *         3px line width
           *
           * @type      {number}
           * @apioption plotOptions.series.marker.states.hover.lineWidth
           */
          /**
           * The radius of the point marker. In hover state, it
           * defaults to the normal state's radius + 2 as per the
           * [radiusPlus](#plotOptions.series.marker.states.hover.radiusPlus)
           * option.
           *
           * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-radius/
           *         10px radius
           *
           * @type      {number}
           * @apioption plotOptions.series.marker.states.hover.radius
           */
          /**
           * The number of pixels to increase the radius of the
           * hovered point.
           *
           * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
           *         5 pixels greater radius on hover
           * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
           *         5 pixels greater radius on hover
           *
           * @since 4.0.3
           */
          radiusPlus: 2,
          /**
           * The additional line width for a hovered point.
           *
           * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
           *         2 pixels wider on hover
           * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
           *         2 pixels wider on hover
           *
           * @since 4.0.3
           */
          lineWidthPlus: 1,
        },
        /**
         * The appearance of the point marker when selected. In order to
         * allow a point to be selected, set the
         * `series.allowPointSelect` option to true.
         *
         * @declare Highcharts.PointStatesSelectOptionsObject
         */
        select: {
          /**
           * Enable or disable visible feedback for selection.
           *
           * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-enabled/
           *         Disabled select state
           *
           * @type      {boolean}
           * @default   true
           * @apioption plotOptions.series.marker.states.select.enabled
           */
          /**
           * The radius of the point marker. In hover state, it
           * defaults to the normal state's radius + 2.
           *
           * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-radius/
           *         10px radius for selected points
           *
           * @type      {number}
           * @apioption plotOptions.series.marker.states.select.radius
           */
          /**
           * The fill color of the point marker.
           *
           * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-fillcolor/
           *         Solid red discs for selected points
           *
           * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
           */
          fillColor: "#cccccc",
          /**
           * The color of the point marker's outline. When
           * `undefined`, the series' or point's color is used.
           *
           * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linecolor/
           *         Red line color for selected points
           *
           * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
           */
          lineColor: "#000000",
          /**
           * The width of the point marker's outline.
           *
           * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linewidth/
           *         3px line width for selected points
           */
          lineWidth: 2,
        },
      },
    },
    /**
     * Properties for each single point.
     *
     * @declare Highcharts.PlotSeriesPointOptions
     *
     * @private
     */
    point: {
      /**
       * Fires when a point is clicked. One parameter, `event`, is passed
       * to the function, containing common event information.
       *
       * If the `series.allowPointSelect` option is true, the default
       * action for the point's click event is to toggle the point's
       * select state. Returning `false` cancels this action.
       *
       * @sample {highcharts} highcharts/plotoptions/series-point-events-click/
       *         Click marker to alert values
       * @sample {highcharts} highcharts/plotoptions/series-point-events-click-column/
       *         Click column
       * @sample {highcharts} highcharts/plotoptions/series-point-events-click-url/
       *         Go to URL
       * @sample {highmaps} maps/plotoptions/series-point-events-click/
       *         Click marker to display values
       * @sample {highmaps} maps/plotoptions/series-point-events-click-url/
       *         Go to URL
       *
       * @type      {Highcharts.PointClickCallbackFunction}
       * @context   Highcharts.Point
       * @apioption plotOptions.series.point.events.click
       */
      /**
       * Fires when the mouse leaves the area close to the point. One
       * parameter, `event`, is passed to the function, containing common
       * event information.
       *
       * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
       *         Show values in the chart's corner on mouse over
       *
       * @type      {Highcharts.PointMouseOutCallbackFunction}
       * @context   Highcharts.Point
       * @apioption plotOptions.series.point.events.mouseOut
       */
      /**
       * Fires when the mouse enters the area close to the point. One
       * parameter, `event`, is passed to the function, containing common
       * event information.
       *
       * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
       *         Show values in the chart's corner on mouse over
       *
       * @type      {Highcharts.PointMouseOverCallbackFunction}
       * @context   Highcharts.Point
       * @apioption plotOptions.series.point.events.mouseOver
       */
      /**
       * Fires when the point is removed using the `.remove()` method. One
       * parameter, `event`, is passed to the function. Returning `false`
       * cancels the operation.
       *
       * @sample {highcharts} highcharts/plotoptions/series-point-events-remove/
       *         Remove point and confirm
       *
       * @type      {Highcharts.PointRemoveCallbackFunction}
       * @since     1.2.0
       * @context   Highcharts.Point
       * @apioption plotOptions.series.point.events.remove
       */
      /**
       * Fires when the point is selected either programmatically or
       * following a click on the point. One parameter, `event`, is passed
       * to the function. Returning `false` cancels the operation.
       *
       * @sample {highcharts} highcharts/plotoptions/series-point-events-select/
       *         Report the last selected point
       * @sample {highmaps} maps/plotoptions/series-allowpointselect/
       *         Report select and unselect
       *
       * @type      {Highcharts.PointSelectCallbackFunction}
       * @since     1.2.0
       * @context   Highcharts.Point
       * @apioption plotOptions.series.point.events.select
       */
      /**
       * Fires when the point is unselected either programmatically or
       * following a click on the point. One parameter, `event`, is passed
       * to the function.
       *  Returning `false` cancels the operation.
       *
       * @sample {highcharts} highcharts/plotoptions/series-point-events-unselect/
       *         Report the last unselected point
       * @sample {highmaps} maps/plotoptions/series-allowpointselect/
       *         Report select and unselect
       *
       * @type      {Highcharts.PointUnselectCallbackFunction}
       * @since     1.2.0
       * @context   Highcharts.Point
       * @apioption plotOptions.series.point.events.unselect
       */
      /**
       * Fires when the point is updated programmatically through the
       * `.update()` method. One parameter, `event`, is passed to the
       * function. The new point options can be accessed through
       * `event.options`. Returning `false` cancels the operation.
       *
       * @sample {highcharts} highcharts/plotoptions/series-point-events-update/
       *         Confirm point updating
       *
       * @type      {Highcharts.PointUpdateCallbackFunction}
       * @since     1.2.0
       * @context   Highcharts.Point
       * @apioption plotOptions.series.point.events.update
       */
      /**
       * Events for each single point.
       *
       * @declare Highcharts.PointEventsOptionsObject
       */
      events: {},
    },
    /**
     * Options for the series data labels, appearing next to each data
     * point.
     *
     * Since v6.2.0, multiple data labels can be applied to each single
     * point by defining them as an array of configs.
     *
     * In styled mode, the data labels can be styled with the
     * `.highcharts-data-label-box` and `.highcharts-data-label` class names
     * ([see example](https://www.highcharts.com/samples/highcharts/css/series-datalabels)).
     *
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-enabled
     *         Data labels enabled
     * @sample {highcharts} highcharts/plotoptions/series-datalabels-multiple
     *         Multiple data labels on a bar series
     * @sample {highcharts} highcharts/css/series-datalabels
     *         Style mode example
     *
     * @declare Highcharts.DataLabelsOptionsObject
     * @type    {*|Array<*>}
     * @product highcharts highstock highmaps gantt
     *
     * @private
     */
    dataLabels: {
      /**
       * The alignment of the data label compared to the point. If
       * `right`, the right side of the label should be touching the
       * point. For points with an extent, like columns, the alignments
       * also dictates how to align it inside the box, as given with the
       * [inside](#plotOptions.column.dataLabels.inside)
       * option. Can be one of `left`, `center` or `right`.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-align-left/
       *         Left aligned
       * @sample {highcharts} highcharts/plotoptions/bar-datalabels-align-inside-bar/
       *         Data labels inside the bar
       *
       * @type {Highcharts.AlignValue|null}
       */
      align: "center",
      /**
       * Whether to allow data labels to overlap. To make the labels less
       * sensitive for overlapping, the
       * [dataLabels.padding](#plotOptions.series.dataLabels.padding)
       * can be set to 0.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-allowoverlap-false/
       *         Don't allow overlap
       *
       * @type      {boolean}
       * @default   false
       * @since     4.1.0
       * @apioption plotOptions.series.dataLabels.allowOverlap
       */
      /**
       * The background color or gradient for the data label.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
       *         Data labels box options
       * @sample {highmaps} maps/plotoptions/series-datalabels-box/
       *         Data labels box options
       *
       * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @since     2.2.1
       * @apioption plotOptions.series.dataLabels.backgroundColor
       */
      /**
       * The border color for the data label. Defaults to `undefined`.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
       *         Data labels box options
       *
       * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @since     2.2.1
       * @apioption plotOptions.series.dataLabels.borderColor
       */
      /**
       * The border radius in pixels for the data label.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
       *         Data labels box options
       * @sample {highmaps} maps/plotoptions/series-datalabels-box/
       *         Data labels box options
       *
       * @type      {number}
       * @default   0
       * @since     2.2.1
       * @apioption plotOptions.series.dataLabels.borderRadius
       */
      /**
       * The border width in pixels for the data label.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
       *         Data labels box options
       *
       * @type      {number}
       * @default   0
       * @since     2.2.1
       * @apioption plotOptions.series.dataLabels.borderWidth
       */
      /**
       * A class name for the data label. Particularly in styled mode,
       * this can be used to give each series' or point's data label
       * unique styling. In addition to this option, a default color class
       * name is added so that we can give the labels a contrast text
       * shadow.
       *
       * @sample {highcharts} highcharts/css/data-label-contrast/
       *         Contrast text shadow
       * @sample {highcharts} highcharts/css/series-datalabels/
       *         Styling by CSS
       *
       * @type      {string}
       * @since     5.0.0
       * @apioption plotOptions.series.dataLabels.className
       */
      /**
       * The text color for the data labels. Defaults to `undefined`. For
       * certain series types, like column or map, the data labels can be
       * drawn inside the points. In this case the data label will be
       * drawn with maximum contrast by default. Additionally, it will be
       * given a `text-outline` style with the opposite color, to further
       * increase the contrast. This can be overridden by setting the
       * `text-outline` style to `none` in the `dataLabels.style` option.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-color/
       *         Red data labels
       * @sample {highmaps} maps/demo/color-axis/
       *         White data labels
       *
       * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
       * @apioption plotOptions.series.dataLabels.color
       */
      /**
       * Whether to hide data labels that are outside the plot area. By
       * default, the data label is moved inside the plot area according
       * to the
       * [overflow](#plotOptions.series.dataLabels.overflow)
       * option.
       *
       * @type      {boolean}
       * @default   true
       * @since     2.3.3
       * @apioption plotOptions.series.dataLabels.crop
       */
      /**
       * Whether to defer displaying the data labels until the initial
       * series animation has finished.
       *
       * @type      {boolean}
       * @default   true
       * @since     4.0.0
       * @product   highcharts highstock gantt
       * @apioption plotOptions.series.dataLabels.defer
       */
      /**
       * Enable or disable the data labels.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-enabled/
       *         Data labels enabled
       * @sample {highmaps} maps/demo/color-axis/
       *         Data labels enabled
       *
       * @type      {boolean}
       * @default   false
       * @apioption plotOptions.series.dataLabels.enabled
       */
      /**
       * A declarative filter to control of which data labels to display.
       * The declarative filter is designed for use when callback
       * functions are not available, like when the chart options require
       * a pure JSON structure or for use with graphical editors. For
       * programmatic control, use the `formatter` instead, and return
       * `undefined` to disable a single data label.
       *
       * @example
       * filter: {
       *     property: 'percentage',
       *     operator: '>',
       *     value: 4
       * }
       *
       * @sample {highcharts} highcharts/demo/pie-monochrome
       *         Data labels filtered by percentage
       *
       * @declare   Highcharts.DataLabelsFilterOptionsObject
       * @since     6.0.3
       * @apioption plotOptions.series.dataLabels.filter
       */
      /**
       * The operator to compare by. Can be one of `>`, `<`, `>=`, `<=`,
       * `==`, and `===`.
       *
       * @type       {string}
       * @validvalue [">", "<", ">=", "<=", "==", "==="]
       * @apioption  plotOptions.series.dataLabels.filter.operator
       */
      /**
       * The point property to filter by. Point options are passed
       * directly to properties, additionally there are `y` value,
       * `percentage` and others listed under {@link Highcharts.Point}
       * members.
       *
       * @type      {string}
       * @apioption plotOptions.series.dataLabels.filter.property
       */
      /**
       * The value to compare against.
       *
       * @type      {number}
       * @apioption plotOptions.series.dataLabels.filter.value
       */
      /**
       * A
       * [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting)
       * for the data label. Available variables are the same as for
       * `formatter`.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
       *         Add a unit
       * @sample {highmaps} maps/plotoptions/series-datalabels-format/
       *         Formatted value in the data label
       *
       * @type      {string}
       * @default   y
       * @default   point.value
       * @since     3.0
       * @apioption plotOptions.series.dataLabels.format
       */
      // eslint-disable-next-line valid-jsdoc
      /**
       * Callback JavaScript function to format the data label. Note that
       * if a `format` is defined, the format takes precedence and the
       * formatter is ignored.
       *
       * @sample {highmaps} maps/plotoptions/series-datalabels-format/
       *         Formatted value
       *
       * @type {Highcharts.DataLabelsFormatterCallbackFunction}
       */
      formatter: function () {
        var numberFormatter = this.series.chart.numberFormatter;
        return this.y === null ? "" : numberFormatter(this.y, -1);
      },
      /**
       * For points with an extent, like columns or map areas, whether to
       * align the data label inside the box or to the actual value point.
       * Defaults to `false` in most cases, `true` in stacked columns.
       *
       * @type      {boolean}
       * @since     3.0
       * @apioption plotOptions.series.dataLabels.inside
       */
      /**
       * Format for points with the value of null. Works analogously to
       * [format](#plotOptions.series.dataLabels.format). `nullFormat` can
       * be applied only to series which support displaying null points.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
       *         Format data label and tooltip for null point.
       *
       * @type      {boolean|string}
       * @since     7.1.0
       * @apioption plotOptions.series.dataLabels.nullFormat
       */
      /**
       * Callback JavaScript function that defines formatting for points
       * with the value of null. Works analogously to
       * [formatter](#plotOptions.series.dataLabels.formatter).
       * `nullPointFormatter` can be applied only to series which support
       * displaying null points.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-format/
       *         Format data label and tooltip for null point.
       *
       * @type      {Highcharts.DataLabelsFormatterCallbackFunction}
       * @since     7.1.0
       * @apioption plotOptions.series.dataLabels.nullFormatter
       */
      /**
       * How to handle data labels that flow outside the plot area. The
       * default is `"justify"`, which aligns them inside the plot area.
       * For columns and bars, this means it will be moved inside the bar.
       * To display data labels outside the plot area, set `crop` to
       * `false` and `overflow` to `"allow"`.
       *
       * @type       {Highcharts.DataLabelsOverflowValue}
       * @default    justify
       * @since      3.0.6
       * @apioption  plotOptions.series.dataLabels.overflow
       */
      /**
       * When either the `borderWidth` or the `backgroundColor` is set,
       * this is the padding within the box.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
       *         Data labels box options
       * @sample {highmaps} maps/plotoptions/series-datalabels-box/
       *         Data labels box options
       *
       * @since 2.2.1
       */
      padding: 5,
      /**
       * Aligns data labels relative to points. If `center` alignment is
       * not possible, it defaults to `right`.
       *
       * @type      {Highcharts.AlignValue}
       * @default   center
       * @apioption plotOptions.series.dataLabels.position
       */
      /**
       * Text rotation in degrees. Note that due to a more complex
       * structure, backgrounds, borders and padding will be lost on a
       * rotated data label.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
       *         Vertical labels
       *
       * @type      {number}
       * @default   0
       * @apioption plotOptions.series.dataLabels.rotation
       */
      /**
       * The shadow of the box. Works best with `borderWidth` or
       * `backgroundColor`. Since 2.3 the shadow can be an object
       * configuration containing `color`, `offsetX`, `offsetY`, `opacity`
       * and `width`.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-box/
       *         Data labels box options
       *
       * @type      {boolean|Highcharts.ShadowOptionsObject}
       * @default   false
       * @since     2.2.1
       * @apioption plotOptions.series.dataLabels.shadow
       */
      /**
       * The name of a symbol to use for the border around the label.
       * Symbols are predefined functions on the Renderer object.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-shape/
       *         A callout for annotations
       *
       * @type      {string}
       * @default   square
       * @since     4.1.2
       * @apioption plotOptions.series.dataLabels.shape
       */
      /**
       * Styles for the label. The default `color` setting is
       * `"contrast"`, which is a pseudo color that Highcharts picks up
       * and applies the maximum contrast to the underlying point item,
       * for example the bar in a bar chart.
       *
       * The `textOutline` is a pseudo property that applies an outline of
       * the given width with the given color, which by default is the
       * maximum contrast to the text. So a bright text color will result
       * in a black text outline for maximum readability on a mixed
       * background. In some cases, especially with grayscale text, the
       * text outline doesn't work well, in which cases it can be disabled
       * by setting it to `"none"`. When `useHTML` is true, the
       * `textOutline` will not be picked up. In this, case, the same
       * effect can be acheived through the `text-shadow` CSS property.
       *
       * For some series types, where each point has an extent, like for
       * example tree maps, the data label may overflow the point. There
       * are two strategies for handling overflow. By default, the text
       * will wrap to multiple lines. The other strategy is to set
       * `style.textOverflow` to `ellipsis`, which will keep the text on
       * one line plus it will break inside long words.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-style/
       *         Bold labels
       * @sample {highcharts} highcharts/plotOptions/pie-datalabels-overflow/
       *         Long labels truncated with an ellipsis in a pie
       * @sample {highcharts} highcharts/plotOptions/pie-datalabels-overflow-wrap/
       *         Long labels are wrapped in a pie
       * @sample {highmaps} maps/demo/color-axis/
       *         Bold labels
       *
       * @type      {Highcharts.CSSObject}
       * @since     4.1.0
       * @apioption plotOptions.series.dataLabels.style
       */
      style: {
        /** @internal */
        fontSize: "11px",
        /** @internal */
        fontWeight: "bold",
        /** @internal */
        color: "contrast",
        /** @internal */
        textOutline: "1px contrast",
      },
      /**
       * Options for a label text which should follow marker's shape.
       * Border and background are disabled for a label that follows a
       * path.
       *
       * **Note:** Only SVG-based renderer supports this option. Setting
       * `useHTML` to true will disable this option.
       *
       * @declare   Highcharts.DataLabelsTextPathOptionsObject
       * @since     7.1.0
       * @apioption plotOptions.series.dataLabels.textPath
       */
      /**
       * Presentation attributes for the text path.
       *
       * @type      {Highcharts.SVGAttributes}
       * @since     7.1.0
       * @apioption plotOptions.series.dataLabels.textPath.attributes
       */
      /**
       * Enable or disable `textPath` option for link's or marker's data
       * labels.
       *
       * @type      {boolean}
       * @since     7.1.0
       * @apioption plotOptions.series.dataLabels.textPath.enabled
       */
      /**
       * Whether to
       * [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html)
       * to render the labels.
       *
       * @type      {boolean}
       * @default   false
       * @apioption plotOptions.series.dataLabels.useHTML
       */
      /**
       * The vertical alignment of a data label. Can be one of `top`,
       * `middle` or `bottom`. The default value depends on the data, for
       * instance in a column chart, the label is above positive values
       * and below negative values.
       *
       * @type  {Highcharts.VerticalAlignValue|null}
       * @since 2.3.3
       */
      verticalAlign: "bottom",
      /**
       * The x position offset of the label relative to the point in
       * pixels.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
       *         Vertical and positioned
       * @sample {highcharts} highcharts/plotoptions/bar-datalabels-align-inside-bar/
       *         Data labels inside the bar
       */
      x: 0,
      /**
       * The Z index of the data labels. The default Z index puts it above
       * the series. Use a Z index of 2 to display it behind the series.
       *
       * @type      {number}
       * @default   6
       * @since     2.3.5
       * @apioption plotOptions.series.dataLabels.z
       */
      /**
       * The y position offset of the label relative to the point in
       * pixels.
       *
       * @sample {highcharts} highcharts/plotoptions/series-datalabels-rotation/
       *         Vertical and positioned
       */
      y: 0,
    },
    /**
     * When the series contains less points than the crop threshold, all
     * points are drawn, even if the points fall outside the visible plot
     * area at the current zoom. The advantage of drawing all points
     * (including markers and columns), is that animation is performed on
     * updates. On the other hand, when the series contains more points than
     * the crop threshold, the series data is cropped to only contain points
     * that fall within the plot area. The advantage of cropping away
     * invisible points is to increase performance on large series.
     *
     * @since   2.2
     * @product highcharts highstock
     *
     * @private
     */
    cropThreshold: 300,
    /**
     * Opacity of a series parts: line, fill (e.g. area) and dataLabels.
     *
     * @see [states.inactive.opacity](#plotOptions.series.states.inactive.opacity)
     *
     * @since 7.1.0
     *
     * @private
     */
    opacity: 1,
    /**
     * The width of each point on the x axis. For example in a column chart
     * with one value each day, the pointRange would be 1 day (= 24 * 3600
     * * 1000 milliseconds). This is normally computed automatically, but
     * this option can be used to override the automatic value.
     *
     * @product highstock
     *
     * @private
     */
    pointRange: 0,
    /**
     * When this is true, the series will not cause the Y axis to cross
     * the zero plane (or [threshold](#plotOptions.series.threshold) option)
     * unless the data actually crosses the plane.
     *
     * For example, if `softThreshold` is `false`, a series of 0, 1, 2,
     * 3 will make the Y axis show negative values according to the
     * `minPadding` option. If `softThreshold` is `true`, the Y axis starts
     * at 0.
     *
     * @since   4.1.9
     * @product highcharts highstock
     *
     * @private
     */
    softThreshold: true,
    /**
     * @declare Highcharts.SeriesStatesOptionsObject
     */
    states: {
      /**
       * The normal state of a series, or for point items in column, pie
       * and similar series. Currently only used for setting animation
       * when returning to normal state from hover.
       *
       * @declare Highcharts.SeriesStatesNormalOptionsObject
       */
      normal: {
        /**
         * Animation when returning to normal state after hovering.
         *
         * @type {boolean|Highcharts.AnimationOptionsObject}
         */
        animation: true,
      },
      /**
       * Options for the hovered series. These settings override the
       * normal state options when a series is moused over or touched.
       *
       * @declare Highcharts.SeriesStatesHoverOptionsObject
       */
      hover: {
        /**
         * Enable separate styles for the hovered series to visualize
         * that the user hovers either the series itself or the legend.
         *
         * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled/
         *         Line
         * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-column/
         *         Column
         * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-pie/
         *         Pie
         *
         * @type      {boolean}
         * @default   true
         * @since     1.2
         * @apioption plotOptions.series.states.hover.enabled
         */
        /**
         * Animation setting for hovering the graph in line-type series.
         *
         * @type    {boolean|Highcharts.AnimationOptionsObject}
         * @since   5.0.8
         * @product highcharts highstock
         */
        animation: {
          /**
           * The duration of the hover animation in milliseconds. By
           * default the hover state animates quickly in, and slowly
           * back to normal.
           *
           * @internal
           */
          duration: 50,
        },
        /**
         * Pixel width of the graph line. By default this property is
         * undefined, and the `lineWidthPlus` property dictates how much
         * to increase the linewidth from normal state.
         *
         * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidth/
         *         5px line on hover
         *
         * @type      {number}
         * @product   highcharts highstock
         * @apioption plotOptions.series.states.hover.lineWidth
         */
        /**
         * The additional line width for the graph of a hovered series.
         *
         * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
         *         5 pixels wider
         * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
         *         5 pixels wider
         *
         * @since   4.0.3
         * @product highcharts highstock
         */
        lineWidthPlus: 1,
        /**
         * In Highcharts 1.0, the appearance of all markers belonging
         * to the hovered series. For settings on the hover state of the
         * individual point, see
         * [marker.states.hover](#plotOptions.series.marker.states.hover).
         *
         * @deprecated
         *
         * @extends   plotOptions.series.marker
         * @excluding states
         * @product   highcharts highstock
         */
        marker: {
          // lineWidth: base + 1,
          // radius: base + 1
        },
        /**
         * Options for the halo appearing around the hovered point in
         * line-type series as well as outside the hovered slice in pie
         * charts. By default the halo is filled by the current point or
         * series color with an opacity of 0.25\. The halo can be
         * disabled by setting the `halo` option to `null`.
         *
         * In styled mode, the halo is styled with the
         * `.highcharts-halo` class, with colors inherited from
         * `.highcharts-color-{n}`.
         *
         * @sample {highcharts} highcharts/plotoptions/halo/
         *         Halo options
         * @sample {highstock} highcharts/plotoptions/halo/
         *         Halo options
         *
         * @declare Highcharts.SeriesStatesHoverHaloOptionsObject
         * @type    {null|*}
         * @since   4.0
         * @product highcharts highstock
         */
        halo: {
          /**
           * A collection of SVG attributes to override the appearance
           * of the halo, for example `fill`, `stroke` and
           * `stroke-width`.
           *
           * @type      {Highcharts.SVGAttributes}
           * @since     4.0
           * @product   highcharts highstock
           * @apioption plotOptions.series.states.hover.halo.attributes
           */
          /**
           * The pixel size of the halo. For point markers this is the
           * radius of the halo. For pie slices it is the width of the
           * halo outside the slice. For bubbles it defaults to 5 and
           * is the width of the halo outside the bubble.
           *
           * @since   4.0
           * @product highcharts highstock
           */
          size: 10,
          /**
           * Opacity for the halo unless a specific fill is overridden
           * using the `attributes` setting. Note that Highcharts is
           * only able to apply opacity to colors of hex or rgb(a)
           * formats.
           *
           * @since   4.0
           * @product highcharts highstock
           */
          opacity: 0.25,
        },
      },
      /**
       * Specific options for point in selected states, after being
       * selected by
       * [allowPointSelect](#plotOptions.series.allowPointSelect)
       * or programmatically.
       *
       * @sample maps/plotoptions/series-allowpointselect/
       *         Allow point select demo
       *
       * @declare   Highcharts.SeriesStatesSelectOptionsObject
       * @extends   plotOptions.series.states.hover
       * @excluding brightness
       */
      select: {
        animation: {
          /** @internal */
          duration: 0,
        },
      },
      /**
       * The opposite state of a hover for series.
       *
       * @sample highcharts/plotoptions/series-states-inactive-opacity
       *         Disabled inactive state by setting opacity
       *
       * @declare Highcharts.SeriesStatesInactiveOptionsObject
       */
      inactive: {
        /**
         * The animation for entering the inactive state.
         *
         * @type {boolean|Highcharts.AnimationOptionsObject}
         */
        animation: {
          /** @internal */
          duration: 50,
        },
        /**
         * Opacity of series elements (dataLabels, line, area). Set to 1
         * to disable inactive state.
         *
         * @apioption plotOptions.series.states.inactive.opacity
         * @type {number}
         * @sample highcharts/plotoptions/series-states-inactive-opacity
         *         Disabled inactive state
         */
        opacity: 0.2,
      },
    },
    /**
     * Sticky tracking of mouse events. When true, the `mouseOut` event on a
     * series isn't triggered until the mouse moves over another series, or
     * out of the plot area. When false, the `mouseOut` event on a series is
     * triggered when the mouse leaves the area around the series' graph or
     * markers. This also implies the tooltip when not shared. When
     * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
     * will be hidden when moving the mouse between series. Defaults to true
     * for line and area type series, but to false for columns, pies etc.
     *
     * **Note:** The boost module will force this option because of
     * technical limitations.
     *
     * @sample {highcharts} highcharts/plotoptions/series-stickytracking-true/
     *         True by default
     * @sample {highcharts} highcharts/plotoptions/series-stickytracking-false/
     *         False
     *
     * @default {highcharts} true
     * @default {highstock} true
     * @default {highmaps} false
     * @since   2.0
     *
     * @private
     */
    stickyTracking: true,
    /**
     * A configuration object for the tooltip rendering of each single
     * series. Properties are inherited from [tooltip](#tooltip), but only
     * the following properties can be defined on a series level.
     *
     * @declare   Highcharts.SeriesTooltipOptionsObject
     * @since     2.3
     * @extends   tooltip
     * @excluding animation, backgroundColor, borderColor, borderRadius,
     *            borderWidth, className, crosshairs, enabled, formatter,
     *            headerShape, hideDelay, outside, padding, positioner,
     *            shadow, shape, shared, snap, split, style, useHTML
     * @apioption plotOptions.series.tooltip
     */
    /**
     * When a series contains a data array that is longer than this, only
     * one dimensional arrays of numbers, or two dimensional arrays with
     * x and y values are allowed. Also, only the first point is tested,
     * and the rest are assumed to be the same format. This saves expensive
     * data checking and indexing in long series. Set it to `0` disable.
     *
     * Note:
     * In boost mode turbo threshold is forced. Only array of numbers or
     * two dimensional arrays are allowed.
     *
     * @since   2.2
     * @product highcharts highstock gantt
     *
     * @private
     */
    turboThreshold: 1000,
    /**
     * An array defining zones within a series. Zones can be applied to the
     * X axis, Y axis or Z axis for bubbles, according to the `zoneAxis`
     * option. The zone definitions have to be in ascending order regarding
     * to the value.
     *
     * In styled mode, the color zones are styled with the
     * `.highcharts-zone-{n}` class, or custom classed from the `className`
     * option
     * ([view live demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/color-zones/)).
     *
     * @see [zoneAxis](#plotOptions.series.zoneAxis)
     *
     * @sample {highcharts} highcharts/series/color-zones-simple/
     *         Color zones
     * @sample {highstock} highcharts/series/color-zones-simple/
     *         Color zones
     *
     * @declare   Highcharts.SeriesZonesOptionsObject
     * @type      {Array<*>}
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zones
     */
    /**
     * Styled mode only. A custom class name for the zone.
     *
     * @sample highcharts/css/color-zones/
     *         Zones styled by class name
     *
     * @type      {string}
     * @since     5.0.0
     * @apioption plotOptions.series.zones.className
     */
    /**
     * Defines the color of the series.
     *
     * @see [series color](#plotOptions.series.color)
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zones.color
     */
    /**
     * A name for the dash style to use for the graph.
     *
     * @see [plotOptions.series.dashStyle](#plotOptions.series.dashStyle)
     *
     * @sample {highcharts|highstock} highcharts/series/color-zones-dashstyle-dot/
     *         Dashed line indicates prognosis
     *
     * @type      {Highcharts.DashStyleValue}
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zones.dashStyle
     */
    /**
     * Defines the fill color for the series (in area type series)
     *
     * @see [fillColor](#plotOptions.area.fillColor)
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zones.fillColor
     */
    /**
     * The value up to where the zone extends, if undefined the zones
     * stretches to the last value in the series.
     *
     * @type      {number}
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zones.value
     */
    /**
     * When using dual or multiple color axes, this number defines which
     * colorAxis the particular series is connected to. It refers to
     * either the
     * {@link #colorAxis.id|axis id}
     * or the index of the axis in the colorAxis array, with 0 being the
     * first. Set this option to false to prevent a series from connecting
     * to the default color axis.
     *
     * Since v7.2.0 the option can also be an axis id or an axis index
     * instead of a boolean flag.
     *
     * @sample highcharts/coloraxis/coloraxis-with-pie/
     *         Color axis with pie series
     * @sample highcharts/coloraxis/multiple-coloraxis/
     *         Multiple color axis
     *
     * @type      {number|string|boolean}
     * @default   0
     * @product   highcharts highstock highmaps
     * @apioption plotOptions.series.colorAxis
     */
    /**
     * Determines what data value should be used to calculate point color
     * if `colorAxis` is used. Requires to set `min` and `max` if some
     * custom point property is used or if approximation for data grouping
     * is set to `'sum'`.
     *
     * @sample highcharts/coloraxis/custom-color-key/
     *         Custom color key
     * @sample highcharts/coloraxis/changed-default-color-key/
     *         Changed default color key
     *
     * @type      {string}
     * @default   y
     * @since     7.2.0
     * @product   highcharts highstock highmaps
     * @apioption plotOptions.series.colorKey
     */
    /**
     * Determines whether the series should look for the nearest point
     * in both dimensions or just the x-dimension when hovering the series.
     * Defaults to `'xy'` for scatter series and `'x'` for most other
     * series. If the data has duplicate x-values, it is recommended to
     * set this to `'xy'` to allow hovering over all points.
     *
     * Applies only to series types using nearest neighbor search (not
     * direct hover) for tooltip.
     *
     * @sample {highcharts} highcharts/series/findnearestpointby/
     *         Different hover behaviors
     * @sample {highstock} highcharts/series/findnearestpointby/
     *         Different hover behaviors
     * @sample {highmaps} highcharts/series/findnearestpointby/
     *         Different hover behaviors
     *
     * @since      5.0.10
     * @validvalue ["x", "xy"]
     *
     * @private
     */
    findNearestPointBy: "x",
  },
  /* eslint-disable no-invalid-this, valid-jsdoc */
  /** @lends Highcharts.Series.prototype */
  {
    axisTypes: ["xAxis", "yAxis"],
    coll: "series",
    colorCounter: 0,
    cropShoulder: 1,
    directTouch: false,
    eventsToUnbind: [],
    isCartesian: true,
    // each point's x and y values are stored in this.xData and this.yData
    parallelArrays: ["x", "y"],
    pointClass: Point,
    requireSorting: true,
    sorted: true,
    init: function (chart, options) {
      fireEvent(this, "init", { options: options });
      var series = this,
        events,
        chartSeries = chart.series,
        lastSeries;
      // A lookup over those events that are added by _options_ (not
      // programmatically). These are updated through Series.update()
      // (#10861).
      this.eventOptions = this.eventOptions || {};
      /**
       * Read only. The chart that the series belongs to.
       *
       * @name Highcharts.Series#chart
       * @type {Highcharts.Chart}
       */
      series.chart = chart;
      /**
       * Read only. The series' type, like "line", "area", "column" etc.
       * The type in the series options anc can be altered using
       * {@link Series#update}.
       *
       * @name Highcharts.Series#type
       * @type {string}
       */
      /**
       * Read only. The series' current options. To update, use
       * {@link Series#update}.
       *
       * @name Highcharts.Series#options
       * @type {Highcharts.SeriesOptionsType}
       */
      series.options = options = series.setOptions(options);
      series.linkedSeries = [];
      // bind the axes
      series.bindAxes();
      // set some variables
      extend(series, {
        /**
         * The series name as given in the options. Defaults to
         * "Series {n}".
         *
         * @name Highcharts.Series#name
         * @type {string}
         */
        name: options.name,
        state: "",
        /**
         * Read only. The series' visibility state as set by {@link
         * Series#show}, {@link Series#hide}, or in the initial
         * configuration.
         *
         * @name Highcharts.Series#visible
         * @type {boolean}
         */
        visible: options.visible !== false,
        /**
         * Read only. The series' selected state as set by {@link
         * Highcharts.Series#select}.
         *
         * @name Highcharts.Series#selected
         * @type {boolean}
         */
        selected: options.selected === true, // false by default
      });
      // Register event listeners
      events = options.events;
      objectEach(events, function (event, eventType) {
        if (H.isFunction(event)) {
          // If event does not exist, or is changed by Series.update
          if (series.eventOptions[eventType] !== event) {
            // Remove existing if set by option
            if (H.isFunction(series.eventOptions[eventType])) {
              removeEvent(series, eventType, series.eventOptions[eventType]);
            }
            series.eventOptions[eventType] = event;
            addEvent(series, eventType, event);
          }
        }
      });
      if (
        (events && events.click) ||
        (options.point && options.point.events && options.point.events.click) ||
        options.allowPointSelect
      ) {
        chart.runTrackerClick = true;
      }
      series.getColor();
      series.getSymbol();
      // Initialize the parallel data arrays
      series.parallelArrays.forEach(function (key) {
        if (!series[key + "Data"]) {
          series[key + "Data"] = [];
        }
      });
      // Mark cartesian
      if (series.isCartesian) {
        chart.hasCartesianSeries = true;
      }
      // Get the index and register the series in the chart. The index is
      // one more than the current latest series index (#5960).
      if (chartSeries.length) {
        lastSeries = chartSeries[chartSeries.length - 1];
      }
      series._i = pick(lastSeries && lastSeries._i, -1) + 1;
      // Insert the series and re-order all series above the insertion
      // point.
      chart.orderSeries(this.insert(chartSeries));
      // Set options for series with sorting and set data later.
      if (options.dataSorting && options.dataSorting.enabled) {
        series.setDataSortingOptions();
      } else if (!series.points && !series.data) {
        series.setData(options.data, false);
      }
      fireEvent(this, "afterInit");
    },
    /**
     * Insert the series in a collection with other series, either the chart
     * series or yAxis series, in the correct order according to the index
     * option. Used internally when adding series.
     *
     * @private
     * @function Highcharts.Series#insert
     * @param {Array<Highcharts.Series>} collection
     *        A collection of series, like `chart.series` or `xAxis.series`.
     * @return {number}
     *         The index of the series in the collection.
     */
    insert: function (collection) {
      var indexOption = this.options.index,
        i;
      // Insert by index option
      if (isNumber(indexOption)) {
        i = collection.length;
        while (i--) {
          // Loop down until the interted element has higher index
          if (
            indexOption >= pick(collection[i].options.index, collection[i]._i)
          ) {
            collection.splice(i + 1, 0, this);
            break;
          }
        }
        if (i === -1) {
          collection.unshift(this);
        }
        i = i + 1;
        // Or just push it to the end
      } else {
        collection.push(this);
      }
      return pick(i, collection.length - 1);
    },
    /**
     * Set the xAxis and yAxis properties of cartesian series, and register
     * the series in the `axis.series` array.
     *
     * @private
     * @function Highcharts.Series#bindAxes
     * @return {void}
     * @exception 18
     */
    bindAxes: function () {
      var series = this,
        seriesOptions = series.options,
        chart = series.chart,
        axisOptions;
      fireEvent(this, "bindAxes", null, function () {
        // repeat for xAxis and yAxis
        (series.axisTypes || []).forEach(function (AXIS) {
          // loop through the chart's axis objects
          chart[AXIS].forEach(function (axis) {
            axisOptions = axis.options;
            // apply if the series xAxis or yAxis option mathches
            // the number of the axis, or if undefined, use the
            // first axis
            if (
              seriesOptions[AXIS] === axisOptions.index ||
              (typeof seriesOptions[AXIS] !== "undefined" &&
                seriesOptions[AXIS] === axisOptions.id) ||
              (typeof seriesOptions[AXIS] === "undefined" &&
                axisOptions.index === 0)
            ) {
              // register this series in the axis.series lookup
              series.insert(axis.series);
              // set this series.xAxis or series.yAxis reference
              /**
               * Read only. The unique xAxis object associated
               * with the series.
               *
               * @name Highcharts.Series#xAxis
               * @type {Highcharts.Axis}
               */
              /**
               * Read only. The unique yAxis object associated
               * with the series.
               *
               * @name Highcharts.Series#yAxis
               * @type {Highcharts.Axis}
               */
              series[AXIS] = axis;
              // mark dirty for redraw
              axis.isDirty = true;
            }
          });
          // The series needs an X and an Y axis
          if (!series[AXIS] && series.optionalAxis !== AXIS) {
            H.error(18, true, chart);
          }
        });
      });
    },
    /**
     * For simple series types like line and column, the data values are
     * held in arrays like xData and yData for quick lookup to find extremes
     * and more. For multidimensional series like bubble and map, this can
     * be extended with arrays like zData and valueData by adding to the
     * `series.parallelArrays` array.
     *
     * @private
     * @function Highcharts.Series#updateParallelArrays
     * @param {Highcharts.Point} point
     * @param {number|string} i
     * @return {void}
     */
    updateParallelArrays: function (point, i) {
      var series = point.series,
        args = arguments,
        fn = isNumber(i)
          ? // Insert the value in the given position
            function (key) {
              var val =
                key === "y" && series.toYData
                  ? series.toYData(point)
                  : point[key];
              series[key + "Data"][i] = val;
            }
          : // Apply the method specified in i with the following
            // arguments as arguments
            function (key) {
              Array.prototype[i].apply(
                series[key + "Data"],
                Array.prototype.slice.call(args, 2)
              );
            };
      series.parallelArrays.forEach(fn);
    },
    /**
     * Define hasData functions for series. These return true if there
     * are data points on this series within the plot area.
     *
     * @private
     * @function Highcharts.Series#hasData
     * @return {boolean}
     */
    hasData: function () {
      return (
        (this.visible &&
          typeof this.dataMax !== "undefined" &&
          typeof this.dataMin !== "undefined") || // #3703
        (this.visible && this.yData && this.yData.length > 0) // #9758
      );
    },
    /**
     * Return an auto incremented x value based on the pointStart and
     * pointInterval options. This is only used if an x value is not given
     * for the point that calls autoIncrement.
     *
     * @private
     * @function Highcharts.Series#autoIncrement
     * @return {number}
     */
    autoIncrement: function () {
      var options = this.options,
        xIncrement = this.xIncrement,
        date,
        pointInterval,
        pointIntervalUnit = options.pointIntervalUnit,
        time = this.chart.time;
      xIncrement = pick(xIncrement, options.pointStart, 0);
      this.pointInterval = pointInterval = pick(
        this.pointInterval,
        options.pointInterval,
        1
      );
      // Added code for pointInterval strings
      if (pointIntervalUnit) {
        date = new time.Date(xIncrement);
        if (pointIntervalUnit === "day") {
          time.set("Date", date, time.get("Date", date) + pointInterval);
        } else if (pointIntervalUnit === "month") {
          time.set("Month", date, time.get("Month", date) + pointInterval);
        } else if (pointIntervalUnit === "year") {
          time.set(
            "FullYear",
            date,
            time.get("FullYear", date) + pointInterval
          );
        }
        pointInterval = date.getTime() - xIncrement;
      }
      this.xIncrement = xIncrement + pointInterval;
      return xIncrement;
    },
    /**
     * Internal function to set properties for series if data sorting is
     * enabled.
     *
     * @private
     * @function Highcharts.Series#setDataSortingOptions
     * @return {void}
     */
    setDataSortingOptions: function () {
      var options = this.options;
      extend(this, {
        requireSorting: false,
        sorted: false,
        enabledDataSorting: true,
        allowDG: false,
      });
      // To allow unsorted data for column series.
      if (!defined(options.pointRange)) {
        options.pointRange = 1;
      }
    },
    /**
     * Set the series options by merging from the options tree. Called
     * internally on initializing and updating series. This function will
     * not redraw the series. For API usage, use {@link Series#update}.
     * @private
     * @function Highcharts.Series#setOptions
     * @param {Highcharts.SeriesOptionsType} itemOptions
     *        The series options.
     * @return {Highcharts.SeriesOptionsType}
     * @fires Highcharts.Series#event:afterSetOptions
     */
    setOptions: function (itemOptions) {
      var chart = this.chart,
        chartOptions = chart.options,
        plotOptions = chartOptions.plotOptions,
        userOptions = chart.userOptions || {},
        seriesUserOptions = merge(itemOptions),
        options,
        zones,
        zone,
        styledMode = chart.styledMode,
        e = {
          plotOptions: plotOptions,
          userOptions: seriesUserOptions,
        };
      fireEvent(this, "setOptions", e);
      // These may be modified by the event
      var typeOptions = e.plotOptions[this.type],
        userPlotOptions = userOptions.plotOptions || {};
      // use copy to prevent undetected changes (#9762)
      this.userOptions = e.userOptions;
      options = merge(
        typeOptions,
        plotOptions.series,
        // #3881, chart instance plotOptions[type] should trump
        // plotOptions.series
        userOptions.plotOptions && userOptions.plotOptions[this.type],
        seriesUserOptions
      );
      // The tooltip options are merged between global and series specific
      // options. Importance order asscendingly:
      // globals: (1)tooltip, (2)plotOptions.series,
      // (3)plotOptions[this.type]
      // init userOptions with possible later updates: 4-6 like 1-3 and
      // (7)this series options
      this.tooltipOptions = merge(
        defaultOptions.tooltip, // 1
        defaultOptions.plotOptions.series &&
          defaultOptions.plotOptions.series.tooltip, // 2
        defaultOptions.plotOptions[this.type].tooltip, // 3
        chartOptions.tooltip.userOptions, // 4
        plotOptions.series && plotOptions.series.tooltip, // 5
        plotOptions[this.type].tooltip, // 6
        seriesUserOptions.tooltip // 7
      );
      // When shared tooltip, stickyTracking is true by default,
      // unless user says otherwise.
      this.stickyTracking = pick(
        seriesUserOptions.stickyTracking,
        userPlotOptions[this.type] && userPlotOptions[this.type].stickyTracking,
        userPlotOptions.series && userPlotOptions.series.stickyTracking,
        this.tooltipOptions.shared && !this.noSharedTooltip
          ? true
          : options.stickyTracking
      );
      // Delete marker object if not allowed (#1125)
      if (typeOptions.marker === null) {
        delete options.marker;
      }
      // Handle color zones
      this.zoneAxis = options.zoneAxis;
      zones = this.zones = (options.zones || []).slice();
      if (
        (options.negativeColor || options.negativeFillColor) &&
        !options.zones
      ) {
        zone = {
          value: options[this.zoneAxis + "Threshold"] || options.threshold || 0,
          className: "highcharts-negative",
        };
        if (!styledMode) {
          zone.color = options.negativeColor;
          zone.fillColor = options.negativeFillColor;
        }
        zones.push(zone);
      }
      if (zones.length) {
        // Push one extra zone for the rest
        if (defined(zones[zones.length - 1].value)) {
          zones.push(
            styledMode
              ? {}
              : {
                  color: this.color,
                  fillColor: this.fillColor,
                }
          );
        }
      }
      fireEvent(this, "afterSetOptions", { options: options });
      return options;
    },
    /**
     * Return series name in "Series {Number}" format or the one defined by
     * a user. This method can be simply overridden as series name format
     * can vary (e.g. technical indicators).
     *
     * @function Highcharts.Series#getName
     * @return {string}
     *         The series name.
     */
    getName: function () {
      // #4119
      return pick(this.options.name, "Series " + (this.index + 1));
    },
    /**
     * @private
     * @function Highcharts.Series#getCyclic
     * @param {string} prop
     * @param {*} [value]
     * @param {Highcharts.Dictionary<any>} [defaults]
     * @return {void}
     */
    getCyclic: function (prop, value, defaults) {
      var i,
        chart = this.chart,
        userOptions = this.userOptions,
        indexName = prop + "Index",
        counterName = prop + "Counter",
        len = defaults
          ? defaults.length
          : pick(chart.options.chart[prop + "Count"], chart[prop + "Count"]),
        setting;
      if (!value) {
        // Pick up either the colorIndex option, or the _colorIndex
        // after Series.update()
        setting = pick(userOptions[indexName], userOptions["_" + indexName]);
        if (defined(setting)) {
          // after Series.update()
          i = setting;
        } else {
          // #6138
          if (!chart.series.length) {
            chart[counterName] = 0;
          }
          userOptions["_" + indexName] = i = chart[counterName] % len;
          chart[counterName] += 1;
        }
        if (defaults) {
          value = defaults[i];
        }
      }
      // Set the colorIndex
      if (typeof i !== "undefined") {
        this[indexName] = i;
      }
      this[prop] = value;
    },
    /**
     * Get the series' color based on either the options or pulled from
     * global options.
     *
     * @private
     * @function Highcharts.Series#getColor
     * @return {void}
     */
    getColor: function () {
      if (this.chart.styledMode) {
        this.getCyclic("color");
      } else if (this.options.colorByPoint) {
        // #4359, selected slice got series.color even when colorByPoint
        // was set.
        this.options.color = null;
      } else {
        this.getCyclic(
          "color",
          this.options.color || defaultPlotOptions[this.type].color,
          this.chart.options.colors
        );
      }
    },
    /**
     * Get the series' symbol based on either the options or pulled from
     * global options.
     *
     * @private
     * @function Highcharts.Series#getSymbol
     * @return {void}
     */
    getSymbol: function () {
      var seriesMarkerOption = this.options.marker;
      this.getCyclic(
        "symbol",
        seriesMarkerOption.symbol,
        this.chart.options.symbols
      );
    },
    /**
     * Finds the index of an existing point that matches the given point
     * options.
     *
     * @private
     * @function Highcharts.Series#findPointIndex
     * @param    {Highcharts.PointOptionsObject} optionsObject
     *           The options of the point.
     * @param    {number} fromIndex
     *           The index to start searching from, used for optimizing
     *           series with required sorting.
     * @returns  {number|undefined}
     *           Returns the index of a matching point, or undefined if no
     *           match is found.
     */
    findPointIndex: function (optionsObject, fromIndex) {
      var id = optionsObject.id,
        x = optionsObject.x,
        oldData = this.points,
        matchingPoint,
        matchedById,
        pointIndex,
        matchKey,
        dataSorting = this.options.dataSorting;
      if (id) {
        matchingPoint = this.chart.get(id);
      } else if (this.linkedParent || this.enabledDataSorting) {
        matchKey = dataSorting && dataSorting.matchByName ? "name" : "index";
        matchingPoint = H.find(oldData, function (oldPoint) {
          return (
            !oldPoint.touched && oldPoint[matchKey] === optionsObject[matchKey]
          );
        });
        // Add unmatched point as a new point
        if (!matchingPoint) {
          return void 0;
        }
      }
      if (matchingPoint) {
        pointIndex = matchingPoint && matchingPoint.index;
        if (typeof pointIndex !== "undefined") {
          matchedById = true;
        }
      }
      // Search for the same X in the existing data set
      if (typeof pointIndex === "undefined" && isNumber(x)) {
        pointIndex = this.xData.indexOf(x, fromIndex);
      }
      // Reduce pointIndex if data is cropped
      if (
        pointIndex !== -1 &&
        typeof pointIndex !== "undefined" &&
        this.cropped
      ) {
        pointIndex =
          pointIndex >= this.cropStart
            ? pointIndex - this.cropStart
            : pointIndex;
      }
      if (!matchedById && oldData[pointIndex] && oldData[pointIndex].touched) {
        pointIndex = void 0;
      }
      return pointIndex;
    },
    /**
     * @private
     * @borrows LegendSymbolMixin.drawLineMarker as Highcharts.Series#drawLegendSymbol
     */
    drawLegendSymbol: LegendSymbolMixin.drawLineMarker,
    /**
     * Internal function called from setData. If the point count is the same
     * as is was, or if there are overlapping X values, just run
     * Point.update which is cheaper, allows animation, and keeps references
     * to points. This also allows adding or removing points if the X-es
     * don't match.
     *
     * @private
     * @function Highcharts.Series#updateData
     *
     * @param {Array<Highcharts.PointOptionsType>} data
     *
     * @return {boolean}
     */
    updateData: function (data, animation) {
      var options = this.options,
        dataSorting = options.dataSorting,
        oldData = this.points,
        pointsToAdd = [],
        hasUpdatedByKey,
        i,
        point,
        lastIndex,
        requireSorting = this.requireSorting,
        equalLength = data.length === oldData.length,
        succeeded = true;
      this.xIncrement = null;
      // Iterate the new data
      data.forEach(function (pointOptions, i) {
        var id,
          x,
          pointIndex,
          optionsObject =
            (defined(pointOptions) &&
              this.pointClass.prototype.optionsToObject.call(
                { series: this },
                pointOptions
              )) ||
            {};
        // Get the x of the new data point
        x = optionsObject.x;
        id = optionsObject.id;
        if (id || isNumber(x)) {
          pointIndex = this.findPointIndex(optionsObject, lastIndex);
          // Matching X not found
          // or used already due to ununique x values (#8995),
          // add point (but later)
          if (pointIndex === -1 || typeof pointIndex === "undefined") {
            pointsToAdd.push(pointOptions);
            // Matching X found, update
          } else if (
            oldData[pointIndex] &&
            pointOptions !== options.data[pointIndex]
          ) {
            oldData[pointIndex].update(pointOptions, false, null, false);
            // Mark it touched, below we will remove all points that
            // are not touched.
            oldData[pointIndex].touched = true;
            // Speed optimize by only searching after last known
            // index. Performs ~20% bettor on large data sets.
            if (requireSorting) {
              lastIndex = pointIndex + 1;
            }
            // Point exists, no changes, don't remove it
          } else if (oldData[pointIndex]) {
            oldData[pointIndex].touched = true;
          }
          // If the length is equal and some of the nodes had a
          // match in the same position, we don't want to remove
          // non-matches.
          if (
            !equalLength ||
            i !== pointIndex ||
            (dataSorting && dataSorting.enabled) ||
            this.hasDerivedData
          ) {
            hasUpdatedByKey = true;
          }
        } else {
          // Gather all points that are not matched
          pointsToAdd.push(pointOptions);
        }
      }, this);
      // Remove points that don't exist in the updated data set
      if (hasUpdatedByKey) {
        i = oldData.length;
        while (i--) {
          point = oldData[i];
          if (point && !point.touched && point.remove) {
            point.remove(false, animation);
          }
        }
        // If we did not find keys (ids or x-values), and the length is the
        // same, update one-to-one
      } else if (equalLength && (!dataSorting || !dataSorting.enabled)) {
        data.forEach(function (point, i) {
          // .update doesn't exist on a linked, hidden series (#3709)
          // (#10187)
          if (oldData[i].update && point !== oldData[i].y) {
            oldData[i].update(point, false, null, false);
          }
        });
        // Don't add new points since those configs are used above
        pointsToAdd.length = 0;
        // Did not succeed in updating data
      } else {
        succeeded = false;
      }
      oldData.forEach(function (point) {
        if (point) {
          point.touched = false;
        }
      });
      if (!succeeded) {
        return false;
      }
      // Add new points
      pointsToAdd.forEach(function (point) {
        this.addPoint(point, false, null, null, false);
      }, this);
      if (this.xIncrement === null && this.xData && this.xData.length) {
        this.xIncrement = arrayMax(this.xData);
        this.autoIncrement();
      }
      return true;
    },
    /**
     * Apply a new set of data to the series and optionally redraw it. The
     * new data array is passed by reference (except in case of
     * `updatePoints`), and may later be mutated when updating the chart
     * data.
     *
     * Note the difference in behaviour when setting the same amount of
     * points, or a different amount of points, as handled by the
     * `updatePoints` parameter.
     *
     * @sample highcharts/members/series-setdata/
     *         Set new data from a button
     * @sample highcharts/members/series-setdata-pie/
     *         Set data in a pie
     * @sample stock/members/series-setdata/
     *         Set new data in Highstock
     * @sample maps/members/series-setdata/
     *         Set new data in Highmaps
     *
     * @function Highcharts.Series#setData
     *
     * @param {Array<Highcharts.PointOptionsType>} data
     *        Takes an array of data in the same format as described under
     *        `series.{type}.data` for the given series type, for example a
     *        line series would take data in the form described under
     *        [series.line.data](https://api.highcharts.com/highcharts/series.line.data).
     *
     * @param {boolean} [redraw=true]
     *        Whether to redraw the chart after the series is altered. If
     *        doing more operations on the chart, it is a good idea to set
     *        redraw to false and call {@link Chart#redraw} after.
     *
     * @param {boolean|Highcharts.AnimationOptionsObject} [animation]
     *        When the updated data is the same length as the existing data,
     *        points will be updated by default, and animation visualizes
     *        how the points are changed. Set false to disable animation, or
     *        a configuration object to set duration or easing.
     *
     * @param {boolean} [updatePoints=true]
     *        When this is true, points will be updated instead of replaced
     *        whenever possible. This occurs a) when the updated data is the
     *        same length as the existing data, b) when points are matched
     *        by their id's, or c) when points can be matched by X values.
     *        This allows updating with animation and performs better. In
     *        this case, the original array is not passed by reference. Set
     *        `false` to prevent.
     *
     * @return {void}
     */
    setData: function (data, redraw, animation, updatePoints) {
      var series = this,
        oldData = series.points,
        oldDataLength = (oldData && oldData.length) || 0,
        dataLength,
        options = series.options,
        chart = series.chart,
        dataSorting = options.dataSorting,
        firstPoint = null,
        xAxis = series.xAxis,
        i,
        turboThreshold = options.turboThreshold,
        pt,
        xData = this.xData,
        yData = this.yData,
        pointArrayMap = series.pointArrayMap,
        valueCount = pointArrayMap && pointArrayMap.length,
        keys = options.keys,
        indexOfX = 0,
        indexOfY = 1,
        updatedData;
      data = data || [];
      dataLength = data.length;
      redraw = pick(redraw, true);
      if (dataSorting && dataSorting.enabled) {
        data = this.sortData(data);
      }
      // First try to run Point.update which is cheaper, allows animation,
      // and keeps references to points.
      if (
        updatePoints !== false &&
        dataLength &&
        oldDataLength &&
        !series.cropped &&
        !series.hasGroupedData &&
        series.visible &&
        // Soft updating has no benefit in boost, and causes JS error
        // (#8355)
        !series.isSeriesBoosting
      ) {
        updatedData = this.updateData(data, animation);
      }
      if (!updatedData) {
        // Reset properties
        series.xIncrement = null;
        series.colorCounter = 0; // for series with colorByPoint (#1547)
        // Update parallel arrays
        this.parallelArrays.forEach(function (key) {
          series[key + "Data"].length = 0;
        });
        // In turbo mode, only one- or twodimensional arrays of numbers
        // are allowed. The first value is tested, and we assume that
        // all the rest are defined the same way. Although the 'for'
        // loops are similar, they are repeated inside each if-else
        // conditional for max performance.
        if (turboThreshold && dataLength > turboThreshold) {
          firstPoint = series.getFirstValidPoint(data);
          if (isNumber(firstPoint)) {
            // assume all points are numbers
            for (i = 0; i < dataLength; i++) {
              xData[i] = this.autoIncrement();
              yData[i] = data[i];
            }
            // Assume all points are arrays when first point is
          } else if (isArray(firstPoint)) {
            if (valueCount) {
              // [x, low, high] or [x, o, h, l, c]
              for (i = 0; i < dataLength; i++) {
                pt = data[i];
                xData[i] = pt[0];
                yData[i] = pt.slice(1, valueCount + 1);
              }
            } else {
              // [x, y]
              if (keys) {
                indexOfX = keys.indexOf("x");
                indexOfY = keys.indexOf("y");
                indexOfX = indexOfX >= 0 ? indexOfX : 0;
                indexOfY = indexOfY >= 0 ? indexOfY : 1;
              }
              for (i = 0; i < dataLength; i++) {
                pt = data[i];
                xData[i] = pt[indexOfX];
                yData[i] = pt[indexOfY];
              }
            }
          } else {
            // Highcharts expects configs to be numbers or arrays in
            // turbo mode
            H.error(12, false, chart);
          }
        } else {
          for (i = 0; i < dataLength; i++) {
            // stray commas in oldIE:
            if (typeof data[i] !== "undefined") {
              pt = { series: series };
              series.pointClass.prototype.applyOptions.apply(pt, [data[i]]);
              series.updateParallelArrays(pt, i);
            }
          }
        }
        // Forgetting to cast strings to numbers is a common caveat when
        // handling CSV or JSON
        if (yData && isString(yData[0])) {
          H.error(14, true, chart);
        }
        series.data = [];
        series.options.data = series.userOptions.data = data;
        // destroy old points
        i = oldDataLength;
        while (i--) {
          if (oldData[i] && oldData[i].destroy) {
            oldData[i].destroy();
          }
        }
        // reset minRange (#878)
        if (xAxis) {
          xAxis.minRange = xAxis.userMinRange;
        }
        // redraw
        series.isDirty = chart.isDirtyBox = true;
        series.isDirtyData = !!oldData;
        animation = false;
      }
      // Typically for pie series, points need to be processed and
      // generated prior to rendering the legend
      if (options.legendType === "point") {
        this.processData();
        this.generatePoints();
      }
      if (redraw) {
        chart.redraw(animation);
      }
    },
    /**
     * Internal function to sort series data
     *
     * @private
     * @function Highcharts.Series#sortData
     * @param {Array<Highcharts.PointOptionsType>} data
     *        Force data grouping.
     * @return {Array<Highcharts.PointOptionsObject>}
     */
    sortData: function (data) {
      var series = this,
        options = series.options,
        dataSorting = options.dataSorting,
        sortKey = dataSorting.sortKey || "y",
        sortedData,
        getPointOptionsObject = function (series, pointOptions) {
          return (
            (defined(pointOptions) &&
              series.pointClass.prototype.optionsToObject.call(
                {
                  series: series,
                },
                pointOptions
              )) ||
            {}
          );
        };
      data.forEach(function (pointOptions, i) {
        data[i] = getPointOptionsObject(series, pointOptions);
        data[i].index = i;
      }, this);
      // Sorting
      sortedData = data.concat().sort(function (a, b) {
        return isNumber(b[sortKey]) ? b[sortKey] - a[sortKey] : -1;
      });
      // Set x value depending on the position in the array
      sortedData.forEach(function (point, i) {
        point.x = i;
      }, this);
      // Set the same x for linked series points if they don't have their
      // own sorting
      if (series.linkedSeries) {
        series.linkedSeries.forEach(function (linkedSeries) {
          var options = linkedSeries.options,
            seriesData = options.data;
          if (
            (!options.dataSorting || !options.dataSorting.enabled) &&
            seriesData
          ) {
            seriesData.forEach(function (pointOptions, i) {
              seriesData[i] = getPointOptionsObject(linkedSeries, pointOptions);
              if (data[i]) {
                seriesData[i].x = data[i].x;
                seriesData[i].index = i;
              }
            });
            linkedSeries.setData(seriesData, false);
          }
        });
      }
      return data;
    },
    /**
     * Internal function to process the data by cropping away unused data
     * points if the series is longer than the crop threshold. This saves
     * computing time for large series. In Highstock, this function is
     * extended to provide data grouping.
     *
     * @private
     * @function Highcharts.Series#processData
     * @param {boolean} [force]
     *        Force data grouping.
     * @return {boolean|undefined}
     */
    processData: function (force) {
      var series = this,
        // copied during slice operation:
        processedXData = series.xData,
        processedYData = series.yData,
        dataLength = processedXData.length,
        croppedData,
        cropStart = 0,
        cropped,
        distance,
        closestPointRange,
        xAxis = series.xAxis,
        i, // loop variable
        options = series.options,
        cropThreshold = options.cropThreshold,
        getExtremesFromAll =
          series.getExtremesFromAll || options.getExtremesFromAll, // #4599
        isCartesian = series.isCartesian,
        xExtremes,
        val2lin = xAxis && xAxis.val2lin,
        isLog = xAxis && xAxis.isLog,
        throwOnUnsorted = series.requireSorting,
        min,
        max;
      // If the series data or axes haven't changed, don't go through
      // this. Return false to pass the message on to override methods
      // like in data grouping.
      if (
        isCartesian &&
        !series.isDirty &&
        !xAxis.isDirty &&
        !series.yAxis.isDirty &&
        !force
      ) {
        return false;
      }
      if (xAxis) {
        // corrected for log axis (#3053)
        xExtremes = xAxis.getExtremes();
        min = xExtremes.min;
        max = xExtremes.max;
      }
      // optionally filter out points outside the plot area
      if (
        isCartesian &&
        series.sorted &&
        !getExtremesFromAll &&
        (!cropThreshold || dataLength > cropThreshold || series.forceCrop)
      ) {
        // it's outside current extremes
        if (processedXData[dataLength - 1] < min || processedXData[0] > max) {
          processedXData = [];
          processedYData = [];
          // only crop if it's actually spilling out
        } else if (
          series.yData &&
          (processedXData[0] < min || processedXData[dataLength - 1] > max)
        ) {
          croppedData = this.cropData(series.xData, series.yData, min, max);
          processedXData = croppedData.xData;
          processedYData = croppedData.yData;
          cropStart = croppedData.start;
          cropped = true;
        }
      }
      // Find the closest distance between processed points
      i = processedXData.length || 1;
      while (--i) {
        distance = isLog
          ? val2lin(processedXData[i]) - val2lin(processedXData[i - 1])
          : processedXData[i] - processedXData[i - 1];
        if (
          distance > 0 &&
          (typeof closestPointRange === "undefined" ||
            distance < closestPointRange)
        ) {
          closestPointRange = distance;
          // Unsorted data is not supported by the line tooltip, as well
          // as data grouping and navigation in Stock charts (#725) and
          // width calculation of columns (#1900)
        } else if (distance < 0 && throwOnUnsorted) {
          H.error(15, false, series.chart);
          throwOnUnsorted = false; // Only once
        }
      }
      // Record the properties
      series.cropped = cropped; // undefined or true
      series.cropStart = cropStart;
      series.processedXData = processedXData;
      series.processedYData = processedYData;
      series.closestPointRange = series.basePointRange = closestPointRange;
    },
    /**
     * Iterate over xData and crop values between min and max. Returns
     * object containing crop start/end cropped xData with corresponding
     * part of yData, dataMin and dataMax within the cropped range.
     *
     * @private
     * @function Highcharts.Series#cropData
     * @param {Array<number>} xData
     * @param {Array<number>} yData
     * @param {number} min
     * @param {number} max
     * @param {number} [cropShoulder]
     * @return {Highcharts.SeriesCropDataObject}
     */
    cropData: function (xData, yData, min, max, cropShoulder) {
      var dataLength = xData.length,
        cropStart = 0,
        cropEnd = dataLength,
        i,
        j;
      // line-type series need one point outside
      cropShoulder = pick(cropShoulder, this.cropShoulder);
      // iterate up to find slice start
      for (i = 0; i < dataLength; i++) {
        if (xData[i] >= min) {
          cropStart = Math.max(0, i - cropShoulder);
          break;
        }
      }
      // proceed to find slice end
      for (j = i; j < dataLength; j++) {
        if (xData[j] > max) {
          cropEnd = j + cropShoulder;
          break;
        }
      }
      return {
        xData: xData.slice(cropStart, cropEnd),
        yData: yData.slice(cropStart, cropEnd),
        start: cropStart,
        end: cropEnd,
      };
    },
    /**
     * Generate the data point after the data has been processed by cropping
     * away unused points and optionally grouped in Highcharts Stock.
     *
     * @private
     * @function Highcharts.Series#generatePoints
     * @return {void}
     */
    generatePoints: function () {
      var series = this,
        options = series.options,
        dataOptions = options.data,
        data = series.data,
        dataLength,
        processedXData = series.processedXData,
        processedYData = series.processedYData,
        PointClass = series.pointClass,
        processedDataLength = processedXData.length,
        cropStart = series.cropStart || 0,
        cursor,
        hasGroupedData = series.hasGroupedData,
        keys = options.keys,
        point,
        points = [],
        i;
      if (!data && !hasGroupedData) {
        var arr = [];
        arr.length = dataOptions.length;
        data = series.data = arr;
      }
      if (keys && hasGroupedData) {
        // grouped data has already applied keys (#6590)
        series.options.keys = false;
      }
      for (i = 0; i < processedDataLength; i++) {
        cursor = cropStart + i;
        if (!hasGroupedData) {
          point = data[cursor];
          // #970:
          if (!point && typeof dataOptions[cursor] !== "undefined") {
            data[cursor] = point = new PointClass().init(
              series,
              dataOptions[cursor],
              processedXData[i]
            );
          }
        } else {
          // splat the y data in case of ohlc data array
          point = new PointClass().init(
            series,
            [processedXData[i]].concat(splat(processedYData[i]))
          );
          /**
           * Highstock only. If a point object is created by data
           * grouping, it doesn't reflect actual points in the raw
           * data. In this case, the `dataGroup` property holds
           * information that points back to the raw data.
           *
           * - `dataGroup.start` is the index of the first raw data
           *   point in the group.
           *
           * - `dataGroup.length` is the amount of points in the
           *   group.
           *
           * @product highstock
           *
           * @name Highcharts.Point#dataGroup
           * @type {Highcharts.DataGroupingInfoObject|undefined}
           */
          point.dataGroup = series.groupMap[i];
          if (point.dataGroup.options) {
            point.options = point.dataGroup.options;
            extend(point, point.dataGroup.options);
            // Collision of props and options (#9770)
            delete point.dataLabels;
          }
        }
        if (point) {
          // #6279
          /**
           * Contains the point's index in the `Series.points` array.
           *
           * @name Highcharts.Point#index
           * @type {number}
           * @readonly
           */
          point.index = cursor; // For faster access in Point.update
          points[i] = point;
        }
      }
      // restore keys options (#6590)
      series.options.keys = keys;
      // Hide cropped-away points - this only runs when the number of
      // points is above cropThreshold, or when swithching view from
      // non-grouped data to grouped data (#637)
      if (
        data &&
        (processedDataLength !== (dataLength = data.length) || hasGroupedData)
      ) {
        for (i = 0; i < dataLength; i++) {
          // when has grouped data, clear all points
          if (i === cropStart && !hasGroupedData) {
            i += processedDataLength;
          }
          if (data[i]) {
            data[i].destroyElements();
            data[i].plotX = void 0; // #1003
          }
        }
      }
      /**
       * Read only. An array containing those values converted to points.
       * In case the series data length exceeds the `cropThreshold`, or if
       * the data is grouped, `series.data` doesn't contain all the
       * points. Also, in case a series is hidden, the `data` array may be
       * empty. To access raw values, `series.options.data` will always be
       * up to date. `Series.data` only contains the points that have been
       * created on demand. To modify the data, use
       * {@link Highcharts.Series#setData} or
       * {@link Highcharts.Point#update}.
       *
       * @see Series.points
       *
       * @name Highcharts.Series#data
       * @type {Array<Highcharts.Point>}
       */
      series.data = data;
      /**
       * An array containing all currently visible point objects. In case
       * of cropping, the cropped-away points are not part of this array.
       * The `series.points` array starts at `series.cropStart` compared
       * to `series.data` and `series.options.data`. If however the series
       * data is grouped, these can't be correlated one to one. To modify
       * the data, use {@link Highcharts.Series#setData} or
       * {@link Highcharts.Point#update}.
       *
       * @name Highcharts.Series#points
       * @type {Array<Highcharts.Point>}
       */
      series.points = points;
      fireEvent(this, "afterGeneratePoints");
    },
    /**
     * Get current X extremes for the visible data.
     *
     * @private
     * @function Highcharts.Series#getXExtremes
     *
     * @param {Array<number>} xData
     *        The data to inspect. Defaults to the current data within the
     *        visible range.
     * @return {Highcharts.RangeObject}
     */
    getXExtremes: function (xData) {
      return {
        min: arrayMin(xData),
        max: arrayMax(xData),
      };
    },
    /**
     * Calculate Y extremes for the visible data. The result is set as
     * `dataMin` and `dataMax` on the Series item.
     *
     * @private
     * @function Highcharts.Series#getExtremes
     * @param {Array<number>} [yData]
     *        The data to inspect. Defaults to the current data within the
     *        visible range.
     * @return {void}
     */
    getExtremes: function (yData) {
      var xAxis = this.xAxis,
        yAxis = this.yAxis,
        xData = this.processedXData || this.xData,
        yDataLength,
        activeYData = [],
        activeCounter = 0,
        // #2117, need to compensate for log X axis
        xExtremes,
        xMin = 0,
        xMax = 0,
        validValue,
        withinRange,
        // Handle X outside the viewed area. This does not work with
        // non-sorted data like scatter (#7639).
        shoulder = this.requireSorting ? this.cropShoulder : 0,
        positiveValuesOnly = yAxis ? yAxis.positiveValuesOnly : false,
        x,
        y,
        i,
        j;
      yData = yData || this.stackedYData || this.processedYData || [];
      yDataLength = yData.length;
      if (xAxis) {
        xExtremes = xAxis.getExtremes();
        xMin = xExtremes.min;
        xMax = xExtremes.max;
      }
      for (i = 0; i < yDataLength; i++) {
        x = xData[i];
        y = yData[i];
        // For points within the visible range, including the first
        // point outside the visible range (#7061), consider y extremes.
        validValue =
          (isNumber(y) || isArray(y)) &&
          (y.length || y > 0 || !positiveValuesOnly);
        withinRange =
          this.getExtremesFromAll ||
          this.options.getExtremesFromAll ||
          this.cropped ||
          !xAxis || // for colorAxis support
          ((xData[i + shoulder] || x) >= xMin &&
            (xData[i - shoulder] || x) <= xMax);
        if (validValue && withinRange) {
          j = y.length;
          if (j) {
            // array, like ohlc or range data
            while (j--) {
              if (isNumber(y[j])) {
                // #7380, #11513
                activeYData[activeCounter++] = y[j];
              }
            }
          } else {
            activeYData[activeCounter++] = y;
          }
        }
      }
      /**
       * Contains the minimum value of the series' data point.
       * @name Highcharts.Series#dataMin
       * @type {number}
       * @readonly
       */
      this.dataMin = arrayMin(activeYData);
      /**
       * Contains the maximum value of the series' data point.
       * @name Highcharts.Series#dataMax
       * @type {number}
       * @readonly
       */
      this.dataMax = arrayMax(activeYData);
      fireEvent(this, "afterGetExtremes");
    },
    /**
     * Find and return the first non null point in the data
     *
     * @private
     * @function Highcharts.Series.getFirstValidPoint
     * @param {Array<Highcharts.PointOptionsType>} data
     *        Array of options for points
     *
     * @return {Highcharts.PointOptionsType}
     */
    getFirstValidPoint: function (data) {
      var firstPoint = null,
        dataLength = data.length,
        i = 0;
      while (firstPoint === null && i < dataLength) {
        firstPoint = data[i];
        i++;
      }
      return firstPoint;
    },
    /**
     * Translate data points from raw data values to chart specific
     * positioning data needed later in the `drawPoints` and `drawGraph`
     * functions. This function can be overridden in plugins and custom
     * series type implementations.
     *
     * @function Highcharts.Series#translate
     * @return {void}
     * @fires Highcharts.Series#events:translate
     */
    translate: function () {
      if (!this.processedXData) {
        // hidden series
        this.processData();
      }
      this.generatePoints();
      var series = this,
        options = series.options,
        stacking = options.stacking,
        xAxis = series.xAxis,
        categories = xAxis.categories,
        enabledDataSorting = series.enabledDataSorting,
        yAxis = series.yAxis,
        points = series.points,
        dataLength = points.length,
        hasModifyValue = !!series.modifyValue,
        i,
        pointPlacement = series.pointPlacementToXValue(), // #7860
        dynamicallyPlaced = isNumber(pointPlacement),
        threshold = options.threshold,
        stackThreshold = options.startFromThreshold ? threshold : 0,
        plotX,
        plotY,
        lastPlotX,
        stackIndicator,
        zoneAxis = this.zoneAxis || "y",
        closestPointRangePx = Number.MAX_VALUE;
      /**
       * Plotted coordinates need to be within a limited range. Drawing
       * too far outside the viewport causes various rendering issues
       * (#3201, #3923, #7555).
       * @private
       */
      function limitedRange(val) {
        return clamp(val, -1e5, 1e5);
      }
      // Translate each point
      for (i = 0; i < dataLength; i++) {
        var point = points[i],
          xValue = point.x,
          yValue = point.y,
          yBottom = point.low,
          stack =
            stacking &&
            yAxis.stacks[
              (series.negStacks && yValue < (stackThreshold ? 0 : threshold)
                ? "-"
                : "") + series.stackKey
            ],
          pointStack,
          stackValues;
        // Discard disallowed y values for log axes (#3434)
        if (yAxis.positiveValuesOnly && yValue !== null && yValue <= 0) {
          point.isNull = true;
        }
        // Get the plotX translation
        point.plotX = plotX = correctFloat(
          // #5236
          limitedRange(
            xAxis.translate(
              // #3923
              xValue,
              0,
              0,
              0,
              1,
              pointPlacement,
              this.type === "flags"
            )
          ) // #3923
        );
        // Calculate the bottom y value for stacked series
        if (stacking && series.visible && stack && stack[xValue]) {
          stackIndicator = series.getStackIndicator(
            stackIndicator,
            xValue,
            series.index
          );
          if (!point.isNull) {
            pointStack = stack[xValue];
            stackValues = pointStack.points[stackIndicator.key];
          }
        }
        if (isArray(stackValues)) {
          yBottom = stackValues[0];
          yValue = stackValues[1];
          if (
            yBottom === stackThreshold &&
            stackIndicator.key === stack[xValue].base
          ) {
            yBottom = pick(isNumber(threshold) && threshold, yAxis.min);
          }
          // #1200, #1232
          if (yAxis.positiveValuesOnly && yBottom <= 0) {
            yBottom = null;
          }
          point.total = point.stackTotal = pointStack.total;
          point.percentage =
            pointStack.total && (point.y / pointStack.total) * 100;
          point.stackY = yValue;
          // Place the stack label
          // in case of variwide series (where widths of points are
          // different in most cases), stack labels are positioned
          // wrongly, so the call of the setOffset is omited here and
          // labels are correctly positioned later, at the end of the
          // variwide's translate function (#10962)
          if (!series.irregularWidths) {
            pointStack.setOffset(series.pointXOffset || 0, series.barW || 0);
          }
        }
        // Set translated yBottom or remove it
        point.yBottom = defined(yBottom)
          ? limitedRange(yAxis.translate(yBottom, 0, 1, 0, 1))
          : null;
        // general hook, used for Highstock compare mode
        if (hasModifyValue) {
          yValue = series.modifyValue(yValue, point);
        }
        // Set the the plotY value, reset it for redraws
        // #3201
        point.plotY = plotY =
          typeof yValue === "number" && yValue !== Infinity
            ? limitedRange(yAxis.translate(yValue, 0, 1, 0, 1))
            : void 0;
        point.isInside =
          typeof plotY !== "undefined" &&
          plotY >= 0 &&
          plotY <= yAxis.len && // #3519
          plotX >= 0 &&
          plotX <= xAxis.len;
        // Set client related positions for mouse tracking
        point.clientX = dynamicallyPlaced
          ? correctFloat(xAxis.translate(xValue, 0, 0, 0, 1, pointPlacement))
          : plotX; // #1514, #5383, #5518
        // Negative points. For bubble charts, this means negative z
        // values (#9728)
        point.negative =
          point[zoneAxis] < (options[zoneAxis + "Threshold"] || threshold || 0);
        // some API data
        point.category =
          categories && typeof categories[point.x] !== "undefined"
            ? categories[point.x]
            : point.x;
        // Determine auto enabling of markers (#3635, #5099)
        if (!point.isNull && point.visible !== false) {
          if (typeof lastPlotX !== "undefined") {
            closestPointRangePx = Math.min(
              closestPointRangePx,
              Math.abs(plotX - lastPlotX)
            );
          }
          lastPlotX = plotX;
        }
        // Find point zone
        point.zone = this.zones.length && point.getZone();
        // Animate new points with data sorting
        if (!point.graphic && series.group && enabledDataSorting) {
          point.isNew = true;
        }
      }
      series.closestPointRangePx = closestPointRangePx;
      fireEvent(this, "afterTranslate");
    },
    /**
     * Return the series points with null points filtered out.
     *
     * @function Highcharts.Series#getValidPoints
     *
     * @param {Array<Highcharts.Point>} [points]
     *        The points to inspect, defaults to {@link Series.points}.
     *
     * @param {boolean} [insideOnly=false]
     *        Whether to inspect only the points that are inside the visible
     *        view.
     *
     * @param {boolean} [allowNull=false]
     *        Whether to allow null points to pass as valid points.
     *
     * @return {Array<Highcharts.Point>}
     *         The valid points.
     */
    getValidPoints: function (points, insideOnly, allowNull) {
      var chart = this.chart;
      // #3916, #5029, #5085
      return (points || this.points || []).filter(function isValidPoint(point) {
        if (
          insideOnly &&
          !chart.isInsidePlot(point.plotX, point.plotY, chart.inverted)
        ) {
          return false;
        }
        return point.visible !== false && (allowNull || !point.isNull);
      });
    },
    /**
     * Get the clipping for the series. Could be called for a series to
     * initiate animating the clip or to set the final clip (only width
     * and x).
     *
     * @private
     * @function Highcharts.Series#getClip
     * @param  {boolean|Highcharts.AnimationOptionsObject} [animation]
     *         Initialize the animation.
     * @param  {boolean} [finalBox]
     *         Final size for the clip - end state for the animation.
     * @return {Highcharts.Dictionary<number>}
     */
    getClipBox: function (animation, finalBox) {
      var series = this,
        options = series.options,
        chart = series.chart,
        inverted = chart.inverted,
        xAxis = series.xAxis,
        yAxis = xAxis && series.yAxis,
        clipBox;
      if (animation && options.clip === false && yAxis) {
        // support for not clipped series animation (#10450)
        clipBox = inverted
          ? {
              y: -chart.chartWidth + yAxis.len + yAxis.pos,
              height: chart.chartWidth,
              width: chart.chartHeight,
              x: -chart.chartHeight + xAxis.len + xAxis.pos,
            }
          : {
              y: -yAxis.pos,
              height: chart.chartHeight,
              width: chart.chartWidth,
              x: -xAxis.pos,
            };
        // x and width will be changed later when setting for animation
        // initial state in Series.setClip
      } else {
        clipBox = series.clipBox || chart.clipBox;
        if (finalBox) {
          clipBox.width = chart.plotSizeX;
          clipBox.x = 0;
        }
      }
      return !finalBox
        ? clipBox
        : {
            width: clipBox.width,
            x: clipBox.x,
          };
    },
    /**
     * Set the clipping for the series. For animated series it is called
     * twice, first to initiate animating the clip then the second time
     * without the animation to set the final clip.
     *
     * @private
     * @function Highcharts.Series#setClip
     * @param {boolean|Highcharts.AnimationOptionsObject} [animation]
     * @return {void}
     */
    setClip: function (animation) {
      var chart = this.chart,
        options = this.options,
        renderer = chart.renderer,
        inverted = chart.inverted,
        seriesClipBox = this.clipBox,
        clipBox = this.getClipBox(animation),
        sharedClipKey =
          this.sharedClipKey ||
          [
            "_sharedClip",
            animation && animation.duration,
            animation && animation.easing,
            clipBox.height,
            options.xAxis,
            options.yAxis,
          ].join(","), // #4526
        clipRect = chart[sharedClipKey],
        markerClipRect = chart[sharedClipKey + "m"];
      // If a clipping rectangle with the same properties is currently
      // present in the chart, use that.
      if (!clipRect) {
        // When animation is set, prepare the initial positions
        if (animation) {
          clipBox.width = 0;
          if (inverted) {
            clipBox.x =
              chart.plotSizeX + (options.clip !== false ? 0 : chart.plotTop);
          }
          chart[sharedClipKey + "m"] = markerClipRect = renderer.clipRect(
            // include the width of the first marker
            inverted ? chart.plotSizeX + 99 : -99,
            inverted ? -chart.plotLeft : -chart.plotTop,
            99,
            inverted ? chart.chartWidth : chart.chartHeight
          );
        }
        chart[sharedClipKey] = clipRect = renderer.clipRect(clipBox);
        // Create hashmap for series indexes
        clipRect.count = { length: 0 };
      }
      if (animation) {
        if (!clipRect.count[this.index]) {
          clipRect.count[this.index] = true;
          clipRect.count.length += 1;
        }
      }
      if (options.clip !== false || animation) {
        this.group.clip(animation || seriesClipBox ? clipRect : chart.clipRect);
        this.markerGroup.clip(markerClipRect);
        this.sharedClipKey = sharedClipKey;
      }
      // Remove the shared clipping rectangle when all series are shown
      if (!animation) {
        if (clipRect.count[this.index]) {
          delete clipRect.count[this.index];
          clipRect.count.length -= 1;
        }
        if (
          clipRect.count.length === 0 &&
          sharedClipKey &&
          chart[sharedClipKey]
        ) {
          if (!seriesClipBox) {
            chart[sharedClipKey] = chart[sharedClipKey].destroy();
          }
          if (chart[sharedClipKey + "m"]) {
            chart[sharedClipKey + "m"] = chart[sharedClipKey + "m"].destroy();
          }
        }
      }
    },
    /**
     * Animate in the series. Called internally twice. First with the `init`
     * parameter set to true, which sets up the initial state of the
     * animation. Then when ready, it is called with the `init` parameter
     * undefined, in order to perform the actual animation. After the
     * second run, the function is removed.
     *
     * @function Highcharts.Series#animate
     *
     * @param {boolean} [init]
     *        Initialize the animation.
     *
     * @return {void}
     */
    animate: function (init) {
      var series = this,
        chart = series.chart,
        animation = animObject(series.options.animation),
        clipRect,
        sharedClipKey,
        finalBox;
      // Initialize the animation. Set up the clipping rectangle.
      if (init) {
        series.setClip(animation);
        // Run the animation
      } else {
        sharedClipKey = this.sharedClipKey;
        clipRect = chart[sharedClipKey];
        finalBox = series.getClipBox(animation, true);
        if (clipRect) {
          clipRect.animate(finalBox, animation);
        }
        if (chart[sharedClipKey + "m"]) {
          chart[sharedClipKey + "m"].animate(
            {
              width: finalBox.width + 99,
              x: finalBox.x - (chart.inverted ? 0 : 99),
            },
            animation
          );
        }
        // Delete this function to allow it only once
        series.animate = null;
      }
    },
    /**
     * This runs after animation to land on the final plot clipping.
     *
     * @private
     * @function Highcharts.Series#afterAnimate
     * @return {void}
     * @fires Highcharts.Series#event:afterAnimate
     */
    afterAnimate: function () {
      this.setClip();
      fireEvent(this, "afterAnimate");
      this.finishedAnimating = true;
    },
    /**
     * Draw the markers for line-like series types, and columns or other
     * graphical representation for {@link Point} objects for other series
     * types. The resulting element is typically stored as
     * {@link Point.graphic}, and is created on the first call and updated
     * and moved on subsequent calls.
     *
     * @function Highcharts.Series#drawPoints
     */
    drawPoints: function () {
      var series = this,
        points = series.points,
        chart = series.chart,
        i,
        point,
        graphic,
        verb,
        options = series.options,
        seriesMarkerOptions = options.marker,
        pointMarkerOptions,
        hasPointMarker,
        markerGroup = series[series.specialGroup] || series.markerGroup,
        xAxis = series.xAxis,
        markerAttribs,
        globallyEnabled = pick(
          seriesMarkerOptions.enabled,
          !xAxis || xAxis.isRadial ? true : null,
          // Use larger or equal as radius is null in bubbles (#6321)
          series.closestPointRangePx >=
            seriesMarkerOptions.enabledThreshold * seriesMarkerOptions.radius
        );
      if (seriesMarkerOptions.enabled !== false || series._hasPointMarkers) {
        for (i = 0; i < points.length; i++) {
          point = points[i];
          graphic = point.graphic;
          verb = graphic ? "animate" : "attr";
          pointMarkerOptions = point.marker || {};
          hasPointMarker = !!point.marker;
          var shouldDrawMarker =
            ((globallyEnabled &&
              typeof pointMarkerOptions.enabled === "undefined") ||
              pointMarkerOptions.enabled) &&
            !point.isNull &&
            point.visible !== false;
          // only draw the point if y is defined
          if (shouldDrawMarker) {
            // Shortcuts
            var symbol = pick(pointMarkerOptions.symbol, series.symbol);
            markerAttribs = series.markerAttribs(
              point,
              point.selected && "select"
            );
            // Set starting position for point sliding animation.
            if (series.enabledDataSorting) {
              point.startXPos = xAxis.reversed
                ? -markerAttribs.width
                : xAxis.width;
            }
            var isInside = point.isInside !== false;
            if (graphic) {
              // update
              // Since the marker group isn't clipped, each
              // individual marker must be toggled
              graphic[isInside ? "show" : "hide"](isInside).animate(
                markerAttribs
              );
            } else if (
              isInside &&
              (markerAttribs.width > 0 || point.hasImage)
            ) {
              /**
               * The graphic representation of the point.
               * Typically this is a simple shape, like a `rect`
               * for column charts or `path` for line markers, but
               * for some complex series types like boxplot or 3D
               * charts, the graphic may be a `g` element
               * containing other shapes. The graphic is generated
               * the first time {@link Series#drawPoints} runs,
               * and updated and moved on subsequent runs.
               *
               * @name Point#graphic
               * @type {SVGElement}
               */
              point.graphic = graphic = chart.renderer
                .symbol(
                  symbol,
                  markerAttribs.x,
                  markerAttribs.y,
                  markerAttribs.width,
                  markerAttribs.height,
                  hasPointMarker ? pointMarkerOptions : seriesMarkerOptions
                )
                .add(markerGroup);
              // Sliding animation for new points
              if (series.enabledDataSorting && chart.hasRendered) {
                graphic.attr({
                  x: point.startXPos,
                });
                verb = "animate";
              }
            }
            if (graphic && verb === "animate") {
              // update
              // Since the marker group isn't clipped, each
              // individual marker must be toggled
              graphic[isInside ? "show" : "hide"](isInside).animate(
                markerAttribs
              );
            }
            // Presentational attributes
            if (graphic && !chart.styledMode) {
              graphic[verb](
                series.pointAttribs(point, point.selected && "select")
              );
            }
            if (graphic) {
              graphic.addClass(point.getClassName(), true);
            }
          } else if (graphic) {
            point.graphic = graphic.destroy(); // #1269
          }
        }
      }
    },
    /**
     * Get non-presentational attributes for a point. Used internally for
     * both styled mode and classic. Can be overridden for different series
     * types.
     *
     * @see Series#pointAttribs
     *
     * @function Highcharts.Series#markerAttribs
     *
     * @param {Highcharts.Point} point
     *        The Point to inspect.
     *
     * @param {string} [state]
     *        The state, can be either `hover`, `select` or undefined.
     *
     * @return {Highcharts.SVGAttributes}
     *         A hash containing those attributes that are not settable from
     *         CSS.
     */
    markerAttribs: function (point, state) {
      var seriesMarkerOptions = this.options.marker,
        seriesStateOptions,
        pointMarkerOptions = point.marker || {},
        symbol = pointMarkerOptions.symbol || seriesMarkerOptions.symbol,
        pointStateOptions,
        radius = pick(pointMarkerOptions.radius, seriesMarkerOptions.radius),
        attribs;
      // Handle hover and select states
      if (state) {
        seriesStateOptions = seriesMarkerOptions.states[state];
        pointStateOptions =
          pointMarkerOptions.states && pointMarkerOptions.states[state];
        radius = pick(
          pointStateOptions && pointStateOptions.radius,
          seriesStateOptions && seriesStateOptions.radius,
          radius + ((seriesStateOptions && seriesStateOptions.radiusPlus) || 0)
        );
      }
      point.hasImage = symbol && symbol.indexOf("url") === 0;
      if (point.hasImage) {
        radius = 0; // and subsequently width and height is not set
      }
      attribs = {
        // Math.floor for #1843:
        x: Math.floor(point.plotX) - radius,
        y: point.plotY - radius,
      };
      if (radius) {
        attribs.width = attribs.height = 2 * radius;
      }
      return attribs;
    },
    /**
     * Internal function to get presentational attributes for each point.
     * Unlike {@link Series#markerAttribs}, this function should return
     * those attributes that can also be set in CSS. In styled mode,
     * `pointAttribs` won't be called.
     *
     * @private
     * @function Highcharts.Series#pointAttribs
     *
     * @param {Highcharts.Point} [point]
     *        The point instance to inspect.
     *
     * @param {string} [state]
     *        The point state, can be either `hover`, `select` or 'normal'.
     *        If undefined, normal state is assumed.
     *
     * @return {Highcharts.SVGAttributes}
     *         The presentational attributes to be set on the point.
     */
    pointAttribs: function (point, state) {
      var seriesMarkerOptions = this.options.marker,
        seriesStateOptions,
        pointOptions = point && point.options,
        pointMarkerOptions = (pointOptions && pointOptions.marker) || {},
        pointStateOptions,
        color = this.color,
        pointColorOption = pointOptions && pointOptions.color,
        pointColor = point && point.color,
        strokeWidth = pick(
          pointMarkerOptions.lineWidth,
          seriesMarkerOptions.lineWidth
        ),
        zoneColor = point && point.zone && point.zone.color,
        fill,
        stroke,
        opacity = 1;
      color = pointColorOption || zoneColor || pointColor || color;
      fill =
        pointMarkerOptions.fillColor || seriesMarkerOptions.fillColor || color;
      stroke =
        pointMarkerOptions.lineColor || seriesMarkerOptions.lineColor || color;
      // Handle hover and select states
      state = state || "normal";
      if (state) {
        seriesStateOptions = seriesMarkerOptions.states[state];
        pointStateOptions =
          (pointMarkerOptions.states && pointMarkerOptions.states[state]) || {};
        strokeWidth = pick(
          pointStateOptions.lineWidth,
          seriesStateOptions.lineWidth,
          strokeWidth +
            pick(
              pointStateOptions.lineWidthPlus,
              seriesStateOptions.lineWidthPlus,
              0
            )
        );
        fill =
          pointStateOptions.fillColor || seriesStateOptions.fillColor || fill;
        stroke =
          pointStateOptions.lineColor || seriesStateOptions.lineColor || stroke;
        opacity = pick(
          pointStateOptions.opacity,
          seriesStateOptions.opacity,
          opacity
        );
      }
      return {
        stroke: stroke,
        "stroke-width": strokeWidth,
        fill: fill,
        opacity: opacity,
      };
    },
    /**
     * Clear DOM objects and free up memory.
     *
     * @private
     * @function Highcharts.Series#destroy
     * @param {boolean} [keepEventsForUpdate]
     * @return {void}
     * @fires Highcharts.Series#event:destroy
     */
    destroy: function (keepEventsForUpdate) {
      var series = this,
        chart = series.chart,
        issue134 = /AppleWebKit\/533/.test(win.navigator.userAgent),
        destroy,
        i,
        data = series.data || [],
        point,
        axis;
      // add event hook
      fireEvent(series, "destroy");
      // remove events
      this.removeEvents(keepEventsForUpdate);
      // erase from axes
      (series.axisTypes || []).forEach(function (AXIS) {
        axis = series[AXIS];
        if (axis && axis.series) {
          erase(axis.series, series);
          axis.isDirty = axis.forceRedraw = true;
        }
      });
      // remove legend items
      if (series.legendItem) {
        series.chart.legend.destroyItem(series);
      }
      // destroy all points with their elements
      i = data.length;
      while (i--) {
        point = data[i];
        if (point && point.destroy) {
          point.destroy();
        }
      }
      series.points = null;
      // Clear the animation timeout if we are destroying the series
      // during initial animation
      H.clearTimeout(series.animationTimeout);
      // Destroy all SVGElements associated to the series
      objectEach(series, function (val, prop) {
        // Survive provides a hook for not destroying
        if (val instanceof SVGElement && !val.survive) {
          // issue 134 workaround
          destroy = issue134 && prop === "group" ? "hide" : "destroy";
          val[destroy]();
        }
      });
      // remove from hoverSeries
      if (chart.hoverSeries === series) {
        chart.hoverSeries = null;
      }
      erase(chart.series, series);
      chart.orderSeries();
      // clear all members
      objectEach(series, function (val, prop) {
        if (!keepEventsForUpdate || prop !== "hcEvents") {
          delete series[prop];
        }
      });
    },
    /**
     * Get the graph path.
     *
     * @private
     * @function Highcharts.Series#getGraphPath
     * @param {Array<Highcharts.Point>} points
     * @param {boolean} [nullsAsZeroes]
     * @param {boolean} [connectCliffs]
     * @return {Highcharts.SVGPathArray}
     */
    getGraphPath: function (points, nullsAsZeroes, connectCliffs) {
      var series = this,
        options = series.options,
        step = options.step,
        reversed,
        graphPath = [],
        xMap = [],
        gap;
      points = points || series.points;
      // Bottom of a stack is reversed
      reversed = points.reversed;
      if (reversed) {
        points.reverse();
      }
      // Reverse the steps (#5004)
      step =
        {
          right: 1,
          center: 2,
        }[step] ||
        (step && 3);
      if (step && reversed) {
        step = 4 - step;
      }
      // Remove invalid points, especially in spline (#5015)
      points = this.getValidPoints(
        points,
        false,
        !(options.connectNulls && !nullsAsZeroes && !connectCliffs)
      );
      // Build the line
      points.forEach(function (point, i) {
        var plotX = point.plotX,
          plotY = point.plotY,
          lastPoint = points[i - 1],
          // the path to this point from the previous
          pathToPoint;
        if (
          (point.leftCliff || (lastPoint && lastPoint.rightCliff)) &&
          !connectCliffs
        ) {
          gap = true; // ... and continue
        }
        // Line series, nullsAsZeroes is not handled
        if (point.isNull && !defined(nullsAsZeroes) && i > 0) {
          gap = !options.connectNulls;
          // Area series, nullsAsZeroes is set
        } else if (point.isNull && !nullsAsZeroes) {
          gap = true;
        } else {
          if (i === 0 || gap) {
            pathToPoint = ["M", point.plotX, point.plotY];
            // Generate the spline as defined in the SplineSeries object
          } else if (series.getPointSpline) {
            pathToPoint = series.getPointSpline(points, point, i);
          } else if (step) {
            if (step === 1) {
              // right
              pathToPoint = ["L", lastPoint.plotX, plotY];
            } else if (step === 2) {
              // center
              pathToPoint = [
                "L",
                (lastPoint.plotX + plotX) / 2,
                lastPoint.plotY,
                "L",
                (lastPoint.plotX + plotX) / 2,
                plotY,
              ];
            } else {
              pathToPoint = ["L", plotX, lastPoint.plotY];
            }
            pathToPoint.push("L", plotX, plotY);
          } else {
            // normal line to next point
            pathToPoint = ["L", plotX, plotY];
          }
          // Prepare for animation. When step is enabled, there are
          // two path nodes for each x value.
          xMap.push(point.x);
          if (step) {
            xMap.push(point.x);
            if (step === 2) {
              // step = center (#8073)
              xMap.push(point.x);
            }
          }
          graphPath.push.apply(graphPath, pathToPoint);
          gap = false;
        }
      });
      graphPath.xMap = xMap;
      series.graphPath = graphPath;
      return graphPath;
    },
    /**
     * Draw the graph. Called internally when rendering line-like series
     * types. The first time it generates the `series.graph` item and
     * optionally other series-wide items like `series.area` for area
     * charts. On subsequent calls these items are updated with new
     * positions and attributes.
     *
     * @function Highcharts.Series#drawGraph
     *
     * @return {void}
     */
    drawGraph: function () {
      var series = this,
        options = this.options,
        graphPath = (this.gappedPath || this.getGraphPath).call(this),
        styledMode = this.chart.styledMode,
        props = [["graph", "highcharts-graph"]];
      // Presentational properties
      if (!styledMode) {
        props[0].push(
          options.lineColor || this.color || "#cccccc", // when colorByPoint = true
          options.dashStyle
        );
      }
      props = series.getZonesGraphs(props);
      // Draw the graph
      props.forEach(function (prop, i) {
        var graphKey = prop[0],
          graph = series[graphKey],
          verb = graph ? "animate" : "attr",
          attribs;
        if (graph) {
          graph.endX = series.preventGraphAnimation ? null : graphPath.xMap;
          graph.animate({ d: graphPath });
        } else if (graphPath.length) {
          // #1487
          /**
           * SVG element of area-based charts. Can be used for styling
           * purposes. If zones are configured, this element will be
           * hidden and replaced by multiple zone areas, accessible
           * via `series['zone-area-x']` (where x is a number,
           * starting with 0).
           *
           * @name Highcharts.Series#area
           * @type {Highcharts.SVGElement|undefined}
           */
          /**
           * SVG element of line-based charts. Can be used for styling
           * purposes. If zones are configured, this element will be
           * hidden and replaced by multiple zone lines, accessible
           * via `series['zone-graph-x']` (where x is a number,
           * starting with 0).
           *
           * @name Highcharts.Series#graph
           * @type {Highcharts.SVGElement|undefined}
           */
          series[graphKey] = graph = series.chart.renderer
            .path(graphPath)
            .addClass(prop[1])
            .attr({ zIndex: 1 }) // #1069
            .add(series.group);
        }
        if (graph && !styledMode) {
          attribs = {
            stroke: prop[2],
            "stroke-width": options.lineWidth,
            // Polygon series use filled graph
            fill: (series.fillGraph && series.color) || "none",
          };
          if (prop[3]) {
            attribs.dashstyle = prop[3];
          } else if (options.linecap !== "square") {
            attribs["stroke-linecap"] = attribs["stroke-linejoin"] = "round";
          }
          graph[verb](attribs)
            // Add shadow to normal series (0) or to first
            // zone (1) #3932
            .shadow(i < 2 && options.shadow);
        }
        // Helpers for animation
        if (graph) {
          graph.startX = graphPath.xMap;
          graph.isArea = graphPath.isArea; // For arearange animation
        }
      });
    },
    /**
     * Get zones properties for building graphs. Extendable by series with
     * multiple lines within one series.
     *
     * @private
     * @function Highcharts.Series#getZonesGraphs
     *
     * @param {Array<Array<string>>} props
     *
     * @return {Array<Array<string>>}
     */
    getZonesGraphs: function (props) {
      // Add the zone properties if any
      this.zones.forEach(function (zone, i) {
        var propset = [
          "zone-graph-" + i,
          "highcharts-graph highcharts-zone-graph-" +
            i +
            " " +
            (zone.className || ""),
        ];
        if (!this.chart.styledMode) {
          propset.push(
            zone.color || this.color,
            zone.dashStyle || this.options.dashStyle
          );
        }
        props.push(propset);
      }, this);
      return props;
    },
    /**
     * Clip the graphs into zones for colors and styling.
     *
     * @private
     * @function Highcharts.Series#applyZones
     * @return {void}
     */
    applyZones: function () {
      var series = this,
        chart = this.chart,
        renderer = chart.renderer,
        zones = this.zones,
        translatedFrom,
        translatedTo,
        clips = this.clips || [],
        clipAttr,
        graph = this.graph,
        area = this.area,
        chartSizeMax = Math.max(chart.chartWidth, chart.chartHeight),
        axis = this[(this.zoneAxis || "y") + "Axis"],
        extremes,
        reversed,
        inverted = chart.inverted,
        horiz,
        pxRange,
        pxPosMin,
        pxPosMax,
        ignoreZones = false;
      if (
        zones.length &&
        (graph || area) &&
        axis &&
        typeof axis.min !== "undefined"
      ) {
        reversed = axis.reversed;
        horiz = axis.horiz;
        // The use of the Color Threshold assumes there are no gaps
        // so it is safe to hide the original graph and area
        // unless it is not waterfall series, then use showLine property
        // to set lines between columns to be visible (#7862)
        if (graph && !this.showLine) {
          graph.hide();
        }
        if (area) {
          area.hide();
        }
        // Create the clips
        extremes = axis.getExtremes();
        zones.forEach(function (threshold, i) {
          translatedFrom = reversed
            ? horiz
              ? chart.plotWidth
              : 0
            : horiz
            ? 0
            : axis.toPixels(extremes.min) || 0;
          translatedFrom = clamp(
            pick(translatedTo, translatedFrom),
            0,
            chartSizeMax
          );
          translatedTo = clamp(
            Math.round(
              axis.toPixels(pick(threshold.value, extremes.max), true) || 0
            ),
            0,
            chartSizeMax
          );
          if (ignoreZones) {
            translatedFrom = translatedTo = axis.toPixels(extremes.max);
          }
          pxRange = Math.abs(translatedFrom - translatedTo);
          pxPosMin = Math.min(translatedFrom, translatedTo);
          pxPosMax = Math.max(translatedFrom, translatedTo);
          if (axis.isXAxis) {
            clipAttr = {
              x: inverted ? pxPosMax : pxPosMin,
              y: 0,
              width: pxRange,
              height: chartSizeMax,
            };
            if (!horiz) {
              clipAttr.x = chart.plotHeight - clipAttr.x;
            }
          } else {
            clipAttr = {
              x: 0,
              y: inverted ? pxPosMax : pxPosMin,
              width: chartSizeMax,
              height: pxRange,
            };
            if (horiz) {
              clipAttr.y = chart.plotWidth - clipAttr.y;
            }
          }
          // VML SUPPPORT
          if (inverted && renderer.isVML) {
            if (axis.isXAxis) {
              clipAttr = {
                x: 0,
                y: reversed ? pxPosMin : pxPosMax,
                height: clipAttr.width,
                width: chart.chartWidth,
              };
            } else {
              clipAttr = {
                x: clipAttr.y - chart.plotLeft - chart.spacingBox.x,
                y: 0,
                width: clipAttr.height,
                height: chart.chartHeight,
              };
            }
          }
          // END OF VML SUPPORT
          if (clips[i]) {
            clips[i].animate(clipAttr);
          } else {
            clips[i] = renderer.clipRect(clipAttr);
          }
          // when no data, graph zone is not applied and after setData
          // clip was ignored. As a result, it should be applied each
          // time.
          if (graph) {
            series["zone-graph-" + i].clip(clips[i]);
          }
          if (area) {
            series["zone-area-" + i].clip(clips[i]);
          }
          // if this zone extends out of the axis, ignore the others
          ignoreZones = threshold.value > extremes.max;
          // Clear translatedTo for indicators
          if (series.resetZones && translatedTo === 0) {
            translatedTo = void 0;
          }
        });
        this.clips = clips;
      } else if (series.visible) {
        // If zones were removed, restore graph and area
        if (graph) {
          graph.show(true);
        }
        if (area) {
          area.show(true);
        }
      }
    },
    /**
     * Initialize and perform group inversion on series.group and
     * series.markerGroup.
     *
     * @private
     * @function Highcharts.Series#invertGroups
     * @param {boolean} [inverted]
     * @return {void}
     */
    invertGroups: function (inverted) {
      var series = this,
        chart = series.chart;
      /**
       * @private
       */
      function setInvert() {
        ["group", "markerGroup"].forEach(function (groupName) {
          if (series[groupName]) {
            // VML/HTML needs explicit attributes for flipping
            if (chart.renderer.isVML) {
              series[groupName].attr({
                width: series.yAxis.len,
                height: series.xAxis.len,
              });
            }
            series[groupName].width = series.yAxis.len;
            series[groupName].height = series.xAxis.len;
            // If inverted polar, don't invert series group
            series[groupName].invert(series.isRadialSeries ? false : inverted);
          }
        });
      }
      // Pie, go away (#1736)
      if (!series.xAxis) {
        return;
      }
      // A fixed size is needed for inversion to work
      series.eventsToUnbind.push(addEvent(chart, "resize", setInvert));
      // Do it now
      setInvert();
      // On subsequent render and redraw, just do setInvert without
      // setting up events again
      series.invertGroups = setInvert;
    },
    /**
     * General abstraction for creating plot groups like series.group,
     * series.dataLabelsGroup and series.markerGroup. On subsequent calls,
     * the group will only be adjusted to the updated plot size.
     *
     * @private
     * @function Highcharts.Series#plotGroup
     * @param {string} prop
     * @param {string} name
     * @param {string} visibility
     * @param {number} [zIndex]
     * @param {Highcharts.SVGElement} [parent]
     * @return {Highcharts.SVGElement}
     */
    plotGroup: function (prop, name, visibility, zIndex, parent) {
      var group = this[prop],
        isNew = !group;
      // Generate it on first call
      if (isNew) {
        this[prop] = group = this.chart.renderer
          .g()
          .attr({
            zIndex: zIndex || 0.1, // IE8 and pointer logic use this
          })
          .add(parent);
      }
      // Add the class names, and replace existing ones as response to
      // Series.update (#6660)
      group.addClass(
        "highcharts-" +
          name +
          " highcharts-series-" +
          this.index +
          " highcharts-" +
          this.type +
          "-series " +
          (defined(this.colorIndex)
            ? "highcharts-color-" + this.colorIndex + " "
            : "") +
          (this.options.className || "") +
          (group.hasClass("highcharts-tracker") ? " highcharts-tracker" : ""),
        true
      );
      // Place it on first and subsequent (redraw) calls
      group
        .attr({ visibility: visibility })
        [isNew ? "attr" : "animate"](this.getPlotBox());
      return group;
    },
    /**
     * Get the translation and scale for the plot area of this series.
     *
     * @function Highcharts.Series#getPlotBox
     *
     * @return {Highcharts.SeriesPlotBoxObject}
     */
    getPlotBox: function () {
      var chart = this.chart,
        xAxis = this.xAxis,
        yAxis = this.yAxis;
      // Swap axes for inverted (#2339)
      if (chart.inverted) {
        xAxis = yAxis;
        yAxis = this.xAxis;
      }
      return {
        translateX: xAxis ? xAxis.left : chart.plotLeft,
        translateY: yAxis ? yAxis.top : chart.plotTop,
        scaleX: 1,
        scaleY: 1,
      };
    },
    /**
     * Removes the event handlers attached previously with addEvents.
     *
     * @private
     * @function Highcharts.Series#removeEvents
     * @param {boolean} [keepEventsForUpdate]
     * @return {void}
     */
    removeEvents: function (keepEventsForUpdate) {
      var series = this;
      if (!keepEventsForUpdate) {
        // remove all events
        removeEvent(series);
      } else if (series.eventsToUnbind.length) {
        // remove only internal events for proper update
        // #12355 - solves problem with multiple destroy events
        series.eventsToUnbind.forEach(function (unbind) {
          unbind();
        });
        series.eventsToUnbind.length = 0;
      }
    },
    /**
     * Render the graph and markers. Called internally when first rendering
     * and later when redrawing the chart. This function can be extended in
     * plugins, but normally shouldn't be called directly.
     *
     * @function Highcharts.Series#render
     *
     * @return {void}
     *
     * @fires Highcharts.Series#event:afterRender
     */
    render: function () {
      var series = this,
        chart = series.chart,
        group,
        options = series.options,
        // Animation doesn't work in IE8 quirks when the group div is
        // hidden, and looks bad in other oldIE
        animDuration =
          !!series.animate &&
          chart.renderer.isSVG &&
          animObject(options.animation).duration,
        visibility = series.visible ? "inherit" : "hidden", // #2597
        zIndex = options.zIndex,
        hasRendered = series.hasRendered,
        chartSeriesGroup = chart.seriesGroup,
        inverted = chart.inverted;
      fireEvent(this, "render");
      // the group
      group = series.plotGroup(
        "group",
        "series",
        visibility,
        zIndex,
        chartSeriesGroup
      );
      series.markerGroup = series.plotGroup(
        "markerGroup",
        "markers",
        visibility,
        zIndex,
        chartSeriesGroup
      );
      // initiate the animation
      if (animDuration) {
        series.animate(true);
      }
      // SVGRenderer needs to know this before drawing elements (#1089,
      // #1795)
      group.inverted =
        series.isCartesian || series.invertable ? inverted : false;
      // Draw the graph if any
      if (series.drawGraph) {
        series.drawGraph();
        series.applyZones();
      }
      // Draw the points
      if (series.visible) {
        series.drawPoints();
      }
      /* series.points.forEach(function (point) {
            if (point.redraw) {
                point.redraw();
            }
        }); */
      // Draw the data labels
      if (series.drawDataLabels) {
        series.drawDataLabels();
      }
      // In pie charts, slices are added to the DOM, but actual rendering
      // is postponed until labels reserved their space
      if (series.redrawPoints) {
        series.redrawPoints();
      }
      // draw the mouse tracking area
      if (series.drawTracker && series.options.enableMouseTracking !== false) {
        series.drawTracker();
      }
      // Handle inverted series and tracker groups
      series.invertGroups(inverted);
      // Initial clipping, must be defined after inverting groups for VML.
      // Applies to columns etc. (#3839).
      if (options.clip !== false && !series.sharedClipKey && !hasRendered) {
        group.clip(chart.clipRect);
      }
      // Run the animation
      if (animDuration) {
        series.animate();
      }
      // Call the afterAnimate function on animation complete (but don't
      // overwrite the animation.complete option which should be available
      // to the user).
      if (!hasRendered) {
        series.animationTimeout = syncTimeout(function () {
          series.afterAnimate();
        }, animDuration || 0);
      }
      // Means data is in accordance with what you see
      series.isDirty = false;
      // (See #322) series.isDirty = series.isDirtyData = false; // means
      // data is in accordance with what you see
      series.hasRendered = true;
      fireEvent(series, "afterRender");
    },
    /**
     * Redraw the series. This function is called internally from
     * `chart.redraw` and normally shouldn't be called directly.
     *
     * @private
     * @function Highcharts.Series#redraw
     * @return {void}
     */
    redraw: function () {
      var series = this,
        chart = series.chart,
        // cache it here as it is set to false in render, but used after
        wasDirty = series.isDirty || series.isDirtyData,
        group = series.group,
        xAxis = series.xAxis,
        yAxis = series.yAxis;
      // reposition on resize
      if (group) {
        if (chart.inverted) {
          group.attr({
            width: chart.plotWidth,
            height: chart.plotHeight,
          });
        }
        group.animate({
          translateX: pick(xAxis && xAxis.left, chart.plotLeft),
          translateY: pick(yAxis && yAxis.top, chart.plotTop),
        });
      }
      series.translate();
      series.render();
      if (wasDirty) {
        // #3868, #3945
        delete this.kdTree;
      }
    },
    kdAxisArray: ["clientX", "plotY"],
    /**
     * @private
     * @function Highcharts.Series#searchPoint
     * @param {Highcharts.PointerEventObject} e
     * @param {boolean} [compareX]
     * @return {Highcharts.Point}
     */
    searchPoint: function (e, compareX) {
      var series = this,
        xAxis = series.xAxis,
        yAxis = series.yAxis,
        inverted = series.chart.inverted;
      return this.searchKDTree(
        {
          clientX: inverted
            ? xAxis.len - e.chartY + xAxis.pos
            : e.chartX - xAxis.pos,
          plotY: inverted
            ? yAxis.len - e.chartX + yAxis.pos
            : e.chartY - yAxis.pos,
        },
        compareX,
        e
      );
    },
    /**
     * Build the k-d-tree that is used by mouse and touch interaction to get
     * the closest point. Line-like series typically have a one-dimensional
     * tree where points are searched along the X axis, while scatter-like
     * series typically search in two dimensions, X and Y.
     *
     * @private
     * @function Highcharts.Series#buildKDTree
     * @param {Highcharts.PointerEventObject} [e]
     * @return {void}
     */
    buildKDTree: function (e) {
      // Prevent multiple k-d-trees from being built simultaneously
      // (#6235)
      this.buildingKdTree = true;
      var series = this,
        dimensions =
          series.options.findNearestPointBy.indexOf("y") > -1 ? 2 : 1;
      /**
       * Internal function
       * @private
       */
      function _kdtree(points, depth, dimensions) {
        var axis,
          median,
          length = points && points.length;
        if (length) {
          // alternate between the axis
          axis = series.kdAxisArray[depth % dimensions];
          // sort point array
          points.sort(function (a, b) {
            return a[axis] - b[axis];
          });
          median = Math.floor(length / 2);
          // build and return nod
          return {
            point: points[median],
            left: _kdtree(points.slice(0, median), depth + 1, dimensions),
            right: _kdtree(points.slice(median + 1), depth + 1, dimensions),
          };
        }
      }
      /**
       * Start the recursive build process with a clone of the points
       * array and null points filtered out. (#3873)
       * @private
       */
      function startRecursive() {
        series.kdTree = _kdtree(
          series.getValidPoints(
            null,
            // For line-type series restrict to plot area, but
            // column-type series not (#3916, #4511)
            !series.directTouch
          ),
          dimensions,
          dimensions
        );
        series.buildingKdTree = false;
      }
      delete series.kdTree;
      // For testing tooltips, don't build async. Also if touchstart, we
      // may be dealing with click events on mobile, so don't delay
      // (#6817).
      syncTimeout(
        startRecursive,
        series.options.kdNow || (e && e.type === "touchstart") ? 0 : 1
      );
    },
    /**
     * @private
     * @function Highcharts.Series#searchKDTree
     * @param {Highcharts.KDPointSearchObject} point
     * @param {boolean} [compareX]
     * @param {Highcharts.PointerEventObject} [e]
     * @return {Highcharts.Point|undefined}
     */
    searchKDTree: function (point, compareX, e) {
      var series = this,
        kdX = this.kdAxisArray[0],
        kdY = this.kdAxisArray[1],
        kdComparer = compareX ? "distX" : "dist",
        kdDimensions =
          series.options.findNearestPointBy.indexOf("y") > -1 ? 2 : 1;
      /**
       * Set the one and two dimensional distance on the point object.
       * @private
       */
      function setDistance(p1, p2) {
        var x =
            defined(p1[kdX]) && defined(p2[kdX])
              ? Math.pow(p1[kdX] - p2[kdX], 2)
              : null,
          y =
            defined(p1[kdY]) && defined(p2[kdY])
              ? Math.pow(p1[kdY] - p2[kdY], 2)
              : null,
          r = (x || 0) + (y || 0);
        p2.dist = defined(r) ? Math.sqrt(r) : Number.MAX_VALUE;
        p2.distX = defined(x) ? Math.sqrt(x) : Number.MAX_VALUE;
      }
      /**
       * @private
       */
      function _search(search, tree, depth, dimensions) {
        var point = tree.point,
          axis = series.kdAxisArray[depth % dimensions],
          tdist,
          sideA,
          sideB,
          ret = point,
          nPoint1,
          nPoint2;
        setDistance(search, point);
        // Pick side based on distance to splitting point
        tdist = search[axis] - point[axis];
        sideA = tdist < 0 ? "left" : "right";
        sideB = tdist < 0 ? "right" : "left";
        // End of tree
        if (tree[sideA]) {
          nPoint1 = _search(search, tree[sideA], depth + 1, dimensions);
          ret = nPoint1[kdComparer] < ret[kdComparer] ? nPoint1 : point;
        }
        if (tree[sideB]) {
          // compare distance to current best to splitting point to
          // decide wether to check side B or not
          if (Math.sqrt(tdist * tdist) < ret[kdComparer]) {
            nPoint2 = _search(search, tree[sideB], depth + 1, dimensions);
            ret = nPoint2[kdComparer] < ret[kdComparer] ? nPoint2 : ret;
          }
        }
        return ret;
      }
      if (!this.kdTree && !this.buildingKdTree) {
        this.buildKDTree(e);
      }
      if (this.kdTree) {
        return _search(point, this.kdTree, kdDimensions, kdDimensions);
      }
    },
    /**
     * @private
     * @function Highcharts.Series#pointPlacementToXValue
     * @return {number}
     */
    pointPlacementToXValue: function () {
      var series = this,
        axis = series.xAxis,
        pointPlacement = series.options.pointPlacement;
      // Point placement is relative to each series pointRange (#5889)
      if (pointPlacement === "between") {
        pointPlacement = axis.reversed ? -0.5 : 0.5; // #11955
      }
      if (isNumber(pointPlacement)) {
        pointPlacement *= pick(series.options.pointRange || axis.pointRange);
      }
      return pointPlacement;
    },
  }
); // end Series prototype
/**
 * A line series displays information as a series of data points connected by
 * straight line segments.
 *
 * @sample {highcharts} highcharts/demo/line-basic/
 *         Line chart
 * @sample {highstock} stock/demo/basic-line/
 *         Line chart
 *
 * @extends   plotOptions.series
 * @product   highcharts highstock
 * @apioption plotOptions.line
 */
/**
 * The SVG value used for the `stroke-linecap` and `stroke-linejoin`
 * of a line graph. Round means that lines are rounded in the ends and
 * bends.
 *
 * @type       {Highcharts.SeriesLinecapValue}
 * @default    round
 * @since      3.0.7
 * @apioption  plotOptions.line.linecap
 */
/**
 * A `line` series. If the [type](#series.line.type) option is not
 * specified, it is inherited from [chart.type](#chart.type).
 *
 * @extends   series,plotOptions.line
 * @excluding dataParser,dataURL
 * @product   highcharts highstock
 * @apioption series.line
 */
/**
 * An array of data points for the series. For the `line` series type,
 * points can be given in the following ways:
 *
 * 1. An array of numerical values. In this case, the numerical values will be
 *    interpreted as `y` options. The `x` values will be automatically
 *    calculated, either starting at 0 and incremented by 1, or from
 *    `pointStart` and `pointInterval` given in the series options. If the axis
 *    has categories, these will be used. Example:
 *    ```js
 *    data: [0, 5, 3, 5]
 *    ```
 *
 * 2. An array of arrays with 2 values. In this case, the values correspond to
 *    `x,y`. If the first value is a string, it is applied as the name of the
 *    point, and the `x` value is inferred.
 *    ```js
 *    data: [
 *        [0, 1],
 *        [1, 2],
 *        [2, 8]
 *    ]
 *    ```
 *
 * 3. An array of objects with named values. The following snippet shows only a
 *    few settings, see the complete options set below. If the total number of
 *    data points exceeds the series'
 *    [turboThreshold](#series.line.turboThreshold),
 *    this option is not available.
 *    ```js
 *    data: [{
 *        x: 1,
 *        y: 9,
 *        name: "Point2",
 *        color: "#00FF00"
 *    }, {
 *        x: 1,
 *        y: 6,
 *        name: "Point1",
 *        color: "#FF00FF"
 *    }]
 *    ```
 *
 * **Note:** In TypeScript you have to extend `PointOptionsObject` with an
 * additional declaration to allow custom data options:
 * ```ts
 * declare module `highcharts` {
 *   interface PointOptionsObject {
 *     customProperty: string;
 *   }
 * }
 * ```
 *
 * @sample {highcharts} highcharts/chart/reflow-true/
 *         Numerical values
 * @sample {highcharts} highcharts/series/data-array-of-arrays/
 *         Arrays of numeric x and y
 * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
 *         Arrays of datetime x and y
 * @sample {highcharts} highcharts/series/data-array-of-name-value/
 *         Arrays of point.name and y
 * @sample {highcharts} highcharts/series/data-array-of-objects/
 *         Config objects
 *
 * @declare   Highcharts.PointOptionsObject
 * @type      {Array<number|Array<(number|string),(number|null)>|null|*>}
 * @apioption series.line.data
 */
/**
 * An additional, individual class name for the data point's graphic
 * representation.
 *
 * @type      {string}
 * @since     5.0.0
 * @product   highcharts gantt
 * @apioption series.line.data.className
 */
/**
 * Individual color for the point. By default the color is pulled from
 * the global `colors` array.
 *
 * In styled mode, the `color` option doesn't take effect. Instead, use
 * `colorIndex`.
 *
 * @sample {highcharts} highcharts/point/color/
 *         Mark the highest point
 *
 * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
 * @product   highcharts highstock gantt
 * @apioption series.line.data.color
 */
/**
 * A specific color index to use for the point, so its graphic representations
 * are given the class name `highcharts-color-{n}`. In styled mode this will
 * change the color of the graphic. In non-styled mode, the color by is set by
 * the `fill` attribute, so the change in class name won't have a visual effect
 * by default.
 *
 * @type      {number}
 * @since     5.0.0
 * @product   highcharts gantt
 * @apioption series.line.data.colorIndex
 */
/**
 * Individual data label for each point. The options are the same as
 * the ones for [plotOptions.series.dataLabels](
 * #plotOptions.series.dataLabels).
 *
 * @sample highcharts/point/datalabels/
 *         Show a label for the last value
 *
 * @declare   Highcharts.DataLabelsOptionsObject
 * @extends   plotOptions.line.dataLabels
 * @product   highcharts highstock gantt
 * @apioption series.line.data.dataLabels
 */
/**
 * A description of the point to add to the screen reader information
 * about the point.
 *
 * @type      {string}
 * @since     5.0.0
 * @requires  modules/accessibility
 * @apioption series.line.data.description
 */
/**
 * An id for the point. This can be used after render time to get a
 * pointer to the point object through `chart.get()`.
 *
 * @sample {highcharts} highcharts/point/id/
 *         Remove an id'd point
 *
 * @type      {string}
 * @since     1.2.0
 * @product   highcharts highstock gantt
 * @apioption series.line.data.id
 */
/**
 * The rank for this point's data label in case of collision. If two
 * data labels are about to overlap, only the one with the highest `labelrank`
 * will be drawn.
 *
 * @type      {number}
 * @apioption series.line.data.labelrank
 */
/**
 * The name of the point as shown in the legend, tooltip, dataLabels, etc.
 *
 * @see [xAxis.uniqueNames](#xAxis.uniqueNames)
 *
 * @sample {highcharts} highcharts/series/data-array-of-objects/
 *         Point names
 *
 * @type      {string}
 * @apioption series.line.data.name
 */
/**
 * Whether the data point is selected initially.
 *
 * @type      {boolean}
 * @default   false
 * @product   highcharts highstock gantt
 * @apioption series.line.data.selected
 */
/**
 * The x value of the point. For datetime axes, the X value is the timestamp
 * in milliseconds since 1970.
 *
 * @type      {number}
 * @product   highcharts highstock
 * @apioption series.line.data.x
 */
/**
 * The y value of the point.
 *
 * @type      {number|null}
 * @product   highcharts highstock
 * @apioption series.line.data.y
 */
/**
 * The individual point events.
 *
 * @extends   plotOptions.series.point.events
 * @product   highcharts highstock gantt
 * @apioption series.line.data.events
 */
/**
 * Options for the point markers of line-like series.
 *
 * @declare   Highcharts.PointMarkerOptionsObject
 * @extends   plotOptions.series.marker
 * @product   highcharts highstock
 * @apioption series.line.data.marker
 */
(""); // include precedent doclets in transpilat
